social_app_template 1.0.3 copy "social_app_template: ^1.0.3" to clipboard
social_app_template: ^1.0.3 copied to clipboard

Package to enable you to create a social app in a very quick way.

Package to enable you to create a social app in a very quick way or at least with as most support as possible by using this template with its functions and widgets.

Source code #

Source code is available on GitLab.

Features #

You can use a set of widgets, repositories and models for your social media app.

List with posts #

Currently, this is the root widget of this package. See Further notes to explore future widgets that will move into a new root widget.

This list consists of posts that are shown in an infinite list that is paged by 7 items. When user scrolls and reaches the 6th post further posts are loaded automatically.

Alt Text
  • Pre-defined object models like user, post, media or location

  • Already full working database (implemented in IsarDB) with repositories and all required CRUD operations

  • Infinite pageable list for your posts

  • Media as images and videos will be cached

  • All videos in list will be played automatically and stopped when visibility of post falls below 40% on scroll

A post is implemented by PostInList widget which shows media, text and creation date of post. As well as post's author image and author name.

When post has media it will show PlatformImageEmbedded for single images and PlatformImageEmbeddedGallery for multiple images and PlatformVideoEmbedded for videos.

Videos are started immediately after they are rendered. You don't need to care about memory issues for long lists with lots of videos. By scrolling videos are paused (when visibility is below 40%), started (when visibility is above 40%) and disposed (when visibility is 0%).

Since a huge amount of users live in regions with slow internet speed or have low Wifi or just want to save mobile data all videos contain PerformanceIndicator. This will show the user if the downloaded quality is at the configured quality. The corresponding switch for configuration will be implemented in the next version.

Getting started #

Add to pubspec.yaml

dependencies:
  social_app_template: ^1.0.0

Then in the console of your project folder

flutter pub get

Prerequisites:

environment:
  sdk: ">=2.12.0 <3.0.0"

Usage #

You can access widgets and functions provided by this package by SocialApp interface. Furthermore you have direct access to the most classes as repositories, model classes and services.

Build list with posts #

Please provide sizes to media objects (see Repositories for additional information).

Otherwise, the list will need some milliseconds to load. First, it will calculate the sizes of images to render.

Provided sizes will allow seamless scrolling with fixed sizes. This also enables caching in appropriate memory size.

You can create a list with posts by calling SocialApp.postList. You should put the list into a sized container since it is still a list that needs constraints.

You can specify the onRefresh function for pull down of your list by user.

@override
Widget@build(BuildContext context){
    final size = MediaQuery.of(context).size;
    
    final postIds = ['post_0', 'post_1'];
    
    SizedBox(
      width: size.width,
      height: size.height,
      child: SocialApp.postList(
        ids: postIds,
        onRefresh: _onRefresh,
      ),
    );

    List<PlatformPost> _onRefresh() {
      return ['post_2', 'post_3'];
    }
}

You can use onInitPost if you like to adjust the post by additional information or to just validate the post before it gets rendered in the list.

@override
Widget build(BuildContext context){
    final size = MediaQuery.of(context).size;
    
    final postIds = ['post_0', 'post_1'];
    
    SizedBox(
      width: size.width,
      height: size.height,
      child: SocialApp.postList(
        ids: postIds,
        onInitPost: _onInitPost,
      ),
    );

    Future<PlatformPost?> _onInitPost(PlatformPost post) async {
      final postWithMySocialMediaApiDetails = await MySocialMediaApi().getPostDetails();
      post.media.addAll(postWithMySocialMediaApiDetails.images);
      return post;
    }
}

If you wish to have a list with a progress indicator just use SocialApp.postListWithProgress.

Make sure to provide progressAlignment in order to position the progress indicator at the right position.

@override
Widget build(BuildContext context){
    final size = MediaQuery.of(context).size;
    
    final postIds = ['post_0', 'post_1'];
    final progressAlignment = const Alignment(0.5, -0.85);
    
    SizedBox(
      width: size.width,
      height: size.height,
      child: SocialApp.postListWithProgress(
        ids: postIds,
        progressAlignment: progressAlignment,
      ),
    );
}

Repositories #

This package provides you the possibility to make all the CRUD operations that you might wish for existing model classes. The existing database is a very fast database that can also handle storage of millions of objects that also have relations and support very specific querying.

Custom repository #

You can also use IsarDB.isar instance to create your own repositories. Just refer to existing code or explore the documentation of Isar.

For the following example of custom repository you will need to run flutter pub run build_runner build in you project folder.

Therefore temporarily you will need to add following dependencies to your pubspec.yaml

dev_dependencies:
  ...
  isar_generator: ^3.0.5
  build_runner: any

In your repository you can use IsarDB.isar instance to implement all the required CRUD operations.

class MyRepository {
  Future<void> create(MyObject){
    await IsarDB.isar.writeTxn(
            () => IsarDB.isar.myObjects.create(),
    );
  }
  
  Future<List<MyObject>> getAllById(Id id){
    return await IsarDB.isar.myObjects
        .where().idEqualsTo(id)
        .findAll();
  }
}

The model object should have a name for the accessor used in the example above in create function.

Additionally Id property is required as the part that will be generated by your execution of flutter pub run build_runner build.

part 'my_object.g.dart';

@Collection(accessor: 'myObjects')
class MyObject {
  Id? id;
}

After the file my_object.g.dart is generated you can now pass the created adapter to the root widget.


@override
Widget build(BuildContext context){
  final size = MediaQuery.of(context).size;

  final postIds = ['post_0', 'post_1'];

  SizedBox(
    width: size.width,
    height: size.height,
    child: SocialApp.postList(
      ids: postIds,
      furtherSchema: [MyObjectSchema],
    ),
  );
}

Repositories of SocialApp Template #

Existing repositories can be called directly without use of the interface SocialApp as in the following examples.

PlatformPostRepository #

Repository to manage model objects of PlatformPost for the posts of your implemented social media.

A PlatformPost should have an author (see PlatformUserRepository for more information). Anyway author property is not marked as required. Without a linked author you won't be able to see the profile image and the name of the author of your social media post in the PostInList widget.

You can include information as urls, hashtags, userMentions or media by using PlatformPostEntities.


void main async {
    final posts =  List.generate(
      2,
          (index) => PlatformPost.of(
              id: '$index',
              entities: PlatformPostEntities.of(
                postId: '$index',
                urls: [
                  'https://mysocialmedia.web/profile/1234'
                ],
                hashtags: [
                  'apple',
                  'fruit',
                ],
                media: [PlatformMedia(
                  id: 'media_0',
                  url: 'https://mysocialmedia.web/image/media_0',
                )],
              )
          ),
    );
  
    await PlatformPostRepository.createAll(posts);
    
    final allCreatedPosts = await PlatformPostRepository.getAll();
    
    /// Should print 2 posts
    print(allCreatedPosts.map((post) => '${post.id}\n').toList());
    
    runApp(myApp());
}

PlatformUserRepository #

Repository to manage model objects of PlatformUser for the users of your implemented social media.

The model allows you to store the location of user as LocationQuery (see LocationQueryRepository for more information).

You should always prefer to create user as embedded object when you call PlatformPostRepository.create. In the following example author and mentionedUser will be persisted and created in database automatically with the post object.


void main async {
  
    final author = PlatformUser.of(
      id: 'user_0',
      name: 'user_name',
      profileImageUrl: 'https://mysocialmedia.web/images/profile/user_0'
    ); 
    
    final mentionedUser = PlatformUser.of(
      id: 'user_1',
      name: 'user_name',
      profileImageUrl: 'https://mysocialmedia.web/images/profile/user_1'
    );
    
    final post =  PlatformPost.of(
              id: 'post_0',
              user: author,
              entities: PlatformPostEntities.of(
                  postId: '$index',
                  userMentions: [mentionedUser],
              )
          );
  
    await PlatformPostRepository.create(post);
    
    final users = await PlatformUserRepository.getAllBy(ids: ['user_0','user_1']);
    
    /// Should print 2 users
    print(users.map((user) => '${user.id}\n').toList());
    
    runApp(myApp());
}

But you can still create and get users without creating it as embedded object by PlatformUserRepository.create.


void main async {
  
    final user = PlatformUser.of(
      id: 'user_0',
      name: 'user_name',
      profileImageUrl: 'https://mysocialmedia.web/images/profile/user_0'
    );
    
    await PlatformUserRepository.create(user);
    
    final storedUser = await PlatformUserRepository.getAsync('user_0');
   
    /// Should print 1 user
    print('${storedUser?.id}\n');
    
    runApp(myApp());
}

LocationQueryRepository #

Repository to manage model objects of LocationQuery for the locations of your implemented social media.

The location consists of following properties:

  • query -> textual representation of location
  • latitude -> the latitude of location
  • longitude -> the longitude of location
  • address -> the address of location

The model allows you to store the address of user as MapBoxPlace object model.

  • Since in my own app I get the information about locations from mapbox.com the structure and the name of this object is inspired by mapbox.
  • In future releases you will be able to get the addresses from mapbox as well.

void main async {
    final location = LocationQuery.of(
      id: 0,
      query: 'Berlin',
      latitude: 52.0,
      longitude: 13.0,
      address: MapBoxPlace.of(
        id: 'place_0',
        text: 'Lindenallee',
        placeName: 'Zentrum, Berlin',
        context: [
          MapBoxPlaceContext(
            id: 'country_place_0',
            mapBoxPlaceId: 'place_0',
            text: 'Germany',
          ),
          MapBoxPlaceContext(
            id: 'city_place_0',
            mapBoxPlaceId: 'place_0',
            text: 'Berlin',
          ),
        ],
      ),
    );
    
    await LocationQueryRepository.create(location);
    
    final locations = await LocationQueryRepository.getByQueryAsync('Berlin');
    
    /// Should print 1 location
    print(locations.map((location) => '${location.query}\n').toList());
    
    runApp(myApp());
}

As mentioned in PlatformUserRepository you should create embedded objects by their parent object. The same rule is applied to locations.

Thus, also the address as MapBoxPlace and its contexts as MapBoxPlaceContext will be persisted and created in database automatically.

For example:

  • you use PlatformUserRepository.create when you create locations for users
  • you use correspondingly PlatformPostRepository.create when you create locations for users in posts

void main async {
    final location = LocationQuery.of(
     ...
      address: MapBoxPlace.of(
        ...
        context: [
          MapBoxPlaceContext(
           ...
          ),
          MapBoxPlaceContext(
            ...
          ),
        ],
      ),
    );
    
    final user = PlatformUser.of(
        id: 'user_0',
        location: location,
    );
    
    await PlatformUserRepository.create(user);
    
    final storedUser = await PlatformUserRepository.getAsync('user_0');
    
    /// Should print 1 location
    print('${storedUser?.location?.value?.query}\n');

    runApp(myApp());
}

Further repositories #

I cannot go into all details here. Feel free to explore and to use further repositories:

  • PlatformMediaRepository
  • PlatformPostEntitiesRepository
  • FocusRepository
  • FocusMetricsRepository
  • MapBoxPlaceRepository
  • MapBoxPlaceContextRepository

As mentioned above you won't need any of these when you want to create new embedded objects like media, location or address. All of embedded objects will be created and persisted when its parent is created.

Since in this package PlatformPost is the root of all model objects it is highly recommended to use PlatformPostRepository.create to persist and to create all of embedded objects.

If you want to update an object please use create function of corresponding repository.

In most cases you have the choice of async or sync GET or GET_ALL in each repository.

You also are able to use delete function in each repository if you want to remove any of objects. You don't need to consider the parent object since the repository will care of indexes.

Further notes #

Feel free to add comments and improvements. I hope it will be fun for you to use this package and you will create your social media or link an existing social media with help of this package in a very quick way.

Future releases will include: #

  • Tap on post in list will open fullscreen of the post
  • Header with a menu and switch between 'users' and 'posts'
  • Grid view to show all users
  • Map view to show all users by their locations
  • Switch between different types of users of your social media
  • User preview as an overlay over the list/grid/map.
  • Filter as an overlay over the list/grid/map.
  • Filter users by age/distance/...

Future releases will replace this dependencies: #

License #

Copyright 2022 Ilja Lichtenberg

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

End license text.