Flutter: Example code for setup and feed query

Based on an example kindly provided by Amity support :pray:

import 'package:amity_sdk/amity_sdk.dart';
import 'package:flutter/material.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await AmityCoreClient.setup(
      option: AmityCoreClientOption(
          apiKey: "<<API_KEY>>",
          httpEndpoint: AmityRegionalHttpEndpoint.EU), // or US or SG
      sycInitialization: true);
  print("successfully setup");
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Amity Social Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Amity User Feed Query Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  final amityPosts = <AmityPost>[];
  late PagingController<AmityPost> _controller;
  final ScrollController scrollcontroller = ScrollController();

  @override
  void initState() {
    AmityCoreClient.login('<<USER_ID>>')
        .displayName('<<USER_ID>>')
        .submit()
        .then((value) {
      print("check login value ${value}");
    });
    super.initState();
  }

  void queryFeed() {
    print("enter query feed");
    _controller = PagingController(
      pageFuture: (token) => AmitySocialClient.newFeedRepository()
          .getUserFeed("<<USER_ID>>") // or community or global feed
          .includeDeleted(false)
          .getPagingData(token: token, limit: 20),
      pageSize: 20,
    )..addListener(
        () {
          if (_controller.error == null) {
            //handle results, we suggest to clear the previous items
            //and add with the latest _controller.loadedItems
            amityPosts.clear();
            amityPosts.addAll(_controller.loadedItems);
            print("check amity post ${amityPosts}");
            //update widgets
          } else {
            print("error getting amity feed");
            //error on pagination controller
            //update widgets
          }
        },
      );
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _controller.fetchNextPage();
    });

    scrollcontroller.addListener(loadMore);
  }

  void loadMore() {
    _controller.fetchNextPage()
        //optional
        .then((value) {
      //success
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              '<Check amityPosts variable for your posts>',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          queryFeed();
        },
        tooltip: 'Query user feed',
        child: const Icon(Icons.add),
      ),
    );
  }
}

1 Like

@devdieter the problem is, you are calling _controller.fetchNextPage() inside the postFrameCallback. but since you are calling the login flow first and adding this callback later, so UI is already rendered and this callback already happen. so _controller.fetchNextPage() never get called.

addPostFrameCallback method
Schedule a callback for the end of this frame. Post-frame callbacks cannot be unregistered. They are called exactly once.

Simple solution would be remove the Post-frame callback.

Hi Sorbh, thanks for commenting on this. It is just intended as a basic code example to help others with a quick start in Flutter.
For us, the postFrameCallback was the key missing ingredient compared to the documentation. Without it, the controller stays empty.
How do you get the first loadedItems from a feed without it?

@devdieter in document we are using postFrameCallback because we assume that user is already logged in and we are trying to load the feed as soon as UI render, so postFrameCallback gives us call back as soon as end of the frame (UI rendering). so we call _controller.fetchNextPage(); inside the postFrameCallback to load the feed after UI is rendered.

but in your case you are query feed on click of FloatingActionButton, in that case you dont need postFrameCallback method. your queryFeed() going to look like this

void queryFeed() {
    print("enter query feed");
    _controller = PagingController(
      pageFuture: (token) => AmitySocialClient.newFeedRepository()
          .getUserFeed("<<USER_ID>>") // or community or global feed
          .includeDeleted(false)
          .getPagingData(token: token, limit: 20),
      pageSize: 20,
    )..addListener(
        () {
          if (_controller.error == null) {
            //handle results, we suggest to clear the previous items
            //and add with the latest _controller.loadedItems
            amityPosts.clear();
            amityPosts.addAll(_controller.loadedItems);
            print("check amity post ${amityPosts}");
            //update widgets
          } else {
            print("error getting amity feed");
            //error on pagination controller
            //update widgets
          }
        },
      );
   // Remove the postFrameCallback
     _controller.fetchNextPage();

    scrollcontroller.addListener(loadMore);
  }

Hope this help :slightly_smiling_face:

Got it! Feel free to add a comment line above postFrameCallback to the example in the first post. I cannot edit the post anymore.