Fliin
On this page

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.

16 of 16 variants pass
Public profile, loaded state
Platform
Brightness
Text scale
Direction

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 profile

Also 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.

Public profile, loaded state
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.

Public profile, following state
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.

Public profile, own state
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.

Public profile, media state
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.

Public profile, loading state
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.

Public profile, error state
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.

Public profile, offline state
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.

Public profile, list state
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.

Public profile, highlights state
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.

Keyenfrar
profileTitleProfileProfilالملف الشخصي
profileBackBackRetourرجوع
profileLoadingLoading the profileChargement du profilجارٍ تحميل الملف الشخصي
profileFollowFollowSuivreمتابعة
profileFollowingButtonFollowingAbonnéتتابعه
profileFollowedYou follow {name}Vous suivez {name}أنت تتابع {name}
profileUnfollowedYou no longer follow {name}Vous ne suivez plus {name}لم تعد تتابع {name}
profileEditEdit profileModifier le profilتعديل الملف الشخصي
profileMessageMessageMessageمراسلة
profileMoreMore actionsPlus d’actionsمزيد من الإجراءات
profilePostPost from {age}: {text}Publication de {age} : {text}منشور {age}: {text}
profileHandle@{handle}@{handle}@{handle}
profilePostsTabPostsPublicationsالمنشورات
profileMediaTabMediaMédiasالوسائط
profilePostsLabelPostsPublicationsمنشورات
profileFollowersLabelFollowersAbonnésمتابِعون
profileFollowingLabelFollowingAbonnementsيتابع
profilePostsOne{count} post{count} publicationمنشور واحد
profilePostsMany{count} posts{count} publicationsالمنشورات: {count}
profileFollowersOne{count} follower{count} abonnéمتابِع واحد
profileFollowersMany{count} followers{count} abonnésالمتابِعون: {count}
profileFollowingOneFollows {count} person{count} abonnementيتابع شخصًا واحدًا
profileFollowingManyFollows {count} people{count} abonnementsيتابع: {count}
profileLikeLike, post from {age}J’aime, publication de {age}إعجاب، منشور {age}
profileLikedLikedJ’aime ajoutéتم الإعجاب
profileUnlikedLike removedJ’aime retiréأُلغي الإعجاب
profileCommentComment, post from {age}Commenter, publication de {age}تعليق، منشور {age}
profileShareShare, post from {age}Partager, publication de {age}مشاركة، منشور {age}
profilePhotoPhoto, post from {age}Photo, publication de {age}صورة، منشور {age}
profilePhotoOfPhoto {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}
profileNoPostsNo posts yet.Aucune publication pour l’instant.لا منشورات بعد.
profileNoMediaNo photos yet.Aucune photo pour l’instant.لا صور بعد.
profileLoadingMoreLoading more postsChargement de la suiteجارٍ تحميل المزيد
profileMoreFailedPosts couldn’t load.Les publications n’ont pas pu se charger.تعذّر تحميل المنشورات.
profileMoreOfflineYou are offline. Posts can’t load.Vous êtes hors ligne. Les publications ne peuvent pas se charger.أنت غير متصل. لا يمكن تحميل المنشورات.
profileFollowFailedCouldn’t update who you follow.Impossible de mettre à jour vos abonnements.تعذّر تحديث من تتابع.
profileLikeFailedYour like wasn’t saved.Votre J’aime n’a pas été enregistré.لم يُحفظ إعجابك.
profileErrorTitleThis profile could not loadImpossible de charger ce profilتعذّر تحميل هذا الملف الشخصي
profileErrorMessageSomething went wrong on our side.Un problème est survenu de notre côté.حدثت مشكلة من جهتنا.
profileOfflineTitleYou are offlineVous êtes hors ligneأنت غير متصل
profileOfflineMessageCheck your connection, then try again.Vérifiez votre connexion, puis réessayez.تحقق من اتصالك ثم أعد المحاولة.
profileRetryTry againRéessayerأعد المحاولة
profileNowNowÀ 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, ٬
profileThousandsK k ألف
profileMillionsM M مليون
profileBillionsB Md مليار
profileDigits01234567890123456789٠١٢٣٤٥٦٧٨٩

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.

iOS · Light
Public profile, iOS, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Public profile, iOS, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Public profile, iOS, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Public profile, iOS, Light, text 2.0×, Right to left
Text 2.0× · Right to left
iOS · Dark
Public profile, iOS, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Public profile, iOS, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Public profile, iOS, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Public profile, iOS, Dark, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Light
Public profile, Android, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Public profile, Android, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Public profile, Android, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Public profile, Android, Light, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Dark
Public profile, Android, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Public profile, Android, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Public profile, Android, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Public profile, Android, Dark, text 2.0×, Right to left
Text 2.0× · Right to left

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
  • Loaded
  • Following
  • Own
  • Media
  • Loading
  • Error
  • Offline

Arrows to move, Enter to open, Escape to close.