amplify_datastore 0.3.0-rc.1 copy "amplify_datastore: ^0.3.0-rc.1" to clipboard
amplify_datastore: ^0.3.0-rc.1 copied to clipboard

outdated

The Amplify Flutter DataStore category plugin, providing a queryable, on-device data store.

example/lib/main.dart

/*
 * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

library sample_app;

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

import 'package:amplify_datastore/amplify_datastore.dart';

// Uncomment the below line to enable online sync
//import 'package:amplify_api/amplify_api.dart';

import 'package:amplify_flutter/amplify.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'amplifyconfiguration.dart';
import 'models/ModelProvider.dart';

part 'queries_display_widgets.dart';
part 'save_model_widgets.dart';
part 'event_display_widgets.dart';

void main() {
  runApp(MyApp());
}

final divider = VerticalDivider(
  color: Colors.white,
  width: 10,
);

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Post> _posts = <Post>[];
  List<Comment> _comments = <Comment>[];
  List<Blog> _blogs = <Blog>[];
  List<Post> _posts4rating = <Post>[];
  List<Post> _posts1To4Rating = <Post>[];
  List<Post> _postWithCreatedDate = <Post>[];
  List<Post> _posts2Or5Rating = <Post>[];
  List<Post> _postWithIdNotEquals = <Post>[];
  List<Post> _firstPostFromResult = <Post>[];
  List<Post> _allPostsWithoutRating2Or5 = <Post>[];
  List<String> _postStreamingData = <String>[];
  List<String> _blogStreamingData = <String>[];
  List<String> _commentStreamingData = <String>[];
  bool _isAmplifyConfigured = false;
  String _queriesToView = "Post"; //default view
  Blog? _selectedBlogForNewPost;
  Post? _selectedPostForNewComment;
  late Stream<SubscriptionEvent<Post>> postStream;
  late Stream<SubscriptionEvent<Blog>> blogStream;
  late Stream<SubscriptionEvent<Comment>> commentStream;
  late StreamSubscription hubSubscription;
  bool _listeningToHub = true;
  late AmplifyDataStore datastorePlugin;

  final _titleController = TextEditingController();
  final _ratingController = TextEditingController();
  final _nameController = TextEditingController();
  final _contentController = TextEditingController();
  ScrollController _postScrollController =
      ScrollController(initialScrollOffset: 50.0);
  ScrollController _blogScrollController =
      ScrollController(initialScrollOffset: 50.0);
  ScrollController _commentScrollController =
      ScrollController(initialScrollOffset: 50.0);

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    try {
      datastorePlugin = AmplifyDataStore(modelProvider: ModelProvider.instance);
      await Amplify.addPlugin(datastorePlugin);

      // Configure

      // Uncomment the below lines to enable online sync.
      // await Amplify.addPlugin(AmplifyAPI());
      // await Amplify.configure(amplifyconfig);

      // Remove this line when using the lines above for online sync
      await Amplify.configure("{}");
    } on AmplifyAlreadyConfiguredException {
      print(
          'Amplify was already configured. Looks like app restarted on android.');
    }
    listenToHub();

    // setup streams
    postStream = Amplify.DataStore.observe(Post.classType);
    postStream.listen((event) {
      _postStreamingData.add('Post: ' +
          (event.eventType.toString() == EventType.delete.toString()
              ? event.item.id
              : event.item.title) +
          ', of type: ' +
          event.eventType.toString());
      runQueries();
    }).onError((error) => print(error));

    blogStream = Amplify.DataStore.observe(Blog.classType);
    blogStream.listen((event) {
      _blogStreamingData.add('Blog: ' +
          (event.eventType.toString() == EventType.delete.toString()
              ? event.item.id
              : event.item.name) +
          ', of type: ' +
          event.eventType.toString());
      runQueries();
    }).onError((error) => print(error));

    commentStream = Amplify.DataStore.observe(Comment.classType);
    commentStream.listen((event) {
      _commentStreamingData.add('Comment: ' +
          (event.eventType.toString() == EventType.delete.toString()
              ? event.item.id
              : event.item.content) +
          ', of type: ' +
          event.eventType.toString());
      runQueries();
    }).onError((error) => print(error));

    setState(() {
      _isAmplifyConfigured = true;
    });
  }

  void listenToHub() {
    setState(() {
      hubSubscription = Amplify.Hub.listen([HubChannel.DataStore], (msg) {
        if (msg.eventName == "ready") {
          runQueries();
        }
        print(msg);
      });
      _listeningToHub = true;
    });
  }

  void stopListeningToHub() {
    hubSubscription.cancel();
    setState(() {
      _listeningToHub = false;
    });
  }

  void runQueries() async {
    List<Post> allPosts = <Post>[];
    List<Comment> allComments = <Comment>[];
    List<Blog> allBlogs = <Blog>[];
    List<Post> posts4Rating = <Post>[];
    List<Post> posts1To4Rating = <Post>[];
    List<Post> posts2Or5Rating = <Post>[];
    List<Post> postWithCreatedDate = <Post>[];
    List<Post> postWithIdNotEquals = <Post>[];
    List<Post> firstPostFromResult = <Post>[];
    List<Post> allPostsWithoutRating2Or5 = <Post>[];

    // get all comments
    (await Amplify.DataStore.query(Comment.classType)).forEach((element) {
      if (element != null) {
        allComments.add(element);
      }
    });

    // get all posts
    (await Amplify.DataStore.query(Post.classType)).forEach((element) {
      if (element != null) {
        allPosts.add(element);
      }
    });

    // get all blogs
    (await Amplify.DataStore.query(Blog.classType)).forEach((element) {
      if (element != null) {
        allBlogs.add(element);
      }
    });

    (await Amplify.DataStore.query(Post.classType, where: Post.RATING.ge(4)))
        .forEach((element) {
      posts4Rating.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            where: Post.RATING.between(1, 4)))
        .forEach((element) {
      posts1To4Rating.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            where: Post.CREATED.eq("2020-02-02T20:20:20-08:00")))
        .forEach((element) {
      postWithCreatedDate.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            where: QueryField(fieldName: "post.id")
                .ne("e25859fc-e254-4e8b-8cae-62ccacce4097")))
        .forEach((element) {
      postWithIdNotEquals.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            where: Post.RATING.eq(2).or(Post.RATING.eq(5))))
        .forEach((element) {
      posts2Or5Rating.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            pagination: QueryPagination.firstResult()))
        .forEach((element) {
      firstPostFromResult.add(element);
    });

    (await Amplify.DataStore.query(Post.classType,
            where: not(Post.RATING.eq(5).or(Post.RATING.eq(2)))))
        .forEach((element) {
      allPostsWithoutRating2Or5.add(element);
    });

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;
    setState(() {
      _posts = allPosts;
      _comments = allComments;
      _blogs = allBlogs;
      _posts1To4Rating = posts1To4Rating;
      _posts4rating = posts4Rating;
      _postWithCreatedDate = postWithCreatedDate;
      _posts2Or5Rating = posts2Or5Rating;
      _postWithIdNotEquals = postWithIdNotEquals;
      _firstPostFromResult = firstPostFromResult;
      _allPostsWithoutRating2Or5 = allPostsWithoutRating2Or5;
    });
  }

  savePost(String title, int rating, Blog associatedBlog) async {
    try {
      Post post = Post(
          title: title,
          rating: rating,
          created: TemporalDateTime.now(),
          blog: associatedBlog);
      await Amplify.DataStore.save(post);
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  saveBlog(String name) async {
    try {
      Blog blog = Blog(
        name: name,
      );
      await Amplify.DataStore.save(blog);
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  saveComment(String content, Post associatedPost) async {
    try {
      Comment comment = Comment(content: content, post: associatedPost);
      await Amplify.DataStore.save(comment);
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  deletePost(String id) async {
    try {
      _selectedPostForNewComment = null;
      await Amplify.DataStore.delete(
          Post(id: id, title: "", rating: 0, created: TemporalDateTime.now()));
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  deleteBlog(String id) async {
    try {
      _selectedBlogForNewPost = null;
      await Amplify.DataStore.delete(Blog(id: id, name: ""));
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  deleteComment(String id) async {
    try {
      await Amplify.DataStore.delete(Comment(id: id, content: ""));
      runQueries();
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    executeAfterBuild();
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text(
            'Best DataStore App Ever',
            textAlign: TextAlign.center,
          ),
          actions: <Widget>[
            Padding(
                padding: EdgeInsets.only(right: 20.0),
                child: GestureDetector(
                  onTap: () async {
                    await Amplify.DataStore.clear();
                    runQueries();
                  },
                  child: Icon(
                    Icons.clear,
                    semanticLabel: "Clear",
                    size: 24.0,
                  ),
                )),
          ],
        ),
        body: Column(
          children: <Widget>[
            Padding(padding: EdgeInsets.all(10.0)),

            // Row for saving blog
            addBlogWidget(_nameController, _isAmplifyConfigured, saveBlog),

            // Row for saving post
            addPostWidget(
                titleController: _titleController,
                ratingController: _ratingController,
                isAmplifyConfigured: _isAmplifyConfigured,
                allBlogs: _blogs,
                saveFn: savePost,
                app: this,
                defaultBlog: _selectedBlogForNewPost),

            // Row for saving comment
            addCommentWidget(_contentController, _isAmplifyConfigured,
                _selectedPostForNewComment, _posts, saveComment, this),

            Padding(padding: EdgeInsets.all(10.0)),

            // Row for query buttons
            displayQueryButtons(_isAmplifyConfigured, this, runQueries),

            Padding(padding: EdgeInsets.all(5.0)),
            Text("Listen to DataStore Hub"),
            Switch(
              value: _listeningToHub,
              onChanged: (value) {
                if (_listeningToHub) {
                  stopListeningToHub();
                } else {
                  listenToHub();
                }
              },
              activeTrackColor: Colors.lightGreenAccent,
              activeColor: Colors.green,
            ),

            Padding(padding: EdgeInsets.all(5.0)),

            // Showing relevant queries
            if (_queriesToView == "Post")
              getWidgetToDisplayPost(_posts, deletePost, _blogs)
            else if (_queriesToView == "Blog")
              getWidgetToDisplayBlog(_blogs, deleteBlog)
            else if (_queriesToView == "Comment")
              getWidgetToDisplayComment(_comments, deleteComment, _posts),

            Text(_queriesToView + " Events",
                style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.black,
                    fontSize: 14)),

            Padding(padding: EdgeInsets.all(5.0)),
            if (_queriesToView == "Post")
              getWidgetToDisplayPostEvents(
                  _postScrollController, _postStreamingData, executeAfterBuild)
            else if (_queriesToView == "Blog")
              getWidgetToDisplayBlogEvents(
                  _blogScrollController, _blogStreamingData, executeAfterBuild)
            else if (_queriesToView == "Comment")
              getWidgetToDisplayCommentEvents(_commentScrollController,
                  _commentStreamingData, executeAfterBuild),
          ],
          // replace with any or all query results as needed
        ),
      ),
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    WidgetsBinding.instance?.addPostFrameCallback((_) => executeAfterBuild());
  }

  Future<void> executeAfterBuild() async {
    // this code will get executed after the build method
    // because of the way async functions are scheduled

    Future.delayed(const Duration(milliseconds: 500), () {
      if (_postScrollController.hasClients)
        _postScrollController.animateTo(
            _postScrollController.position.maxScrollExtent,
            duration: Duration(milliseconds: 200),
            curve: Curves.easeOut);
      if (_blogScrollController.hasClients)
        _blogScrollController.animateTo(
            _blogScrollController.position.maxScrollExtent,
            duration: Duration(milliseconds: 200),
            curve: Curves.easeOut);
      if (_commentScrollController.hasClients)
        _commentScrollController.animateTo(
            _commentScrollController.position.maxScrollExtent,
            duration: Duration(milliseconds: 200),
            curve: Curves.easeOut);
    });
  }
}