RocketChat / Rocket.Chat.Flutter.SDK

Easily integrate Rocket.Chat into all your Flutter projects
MIT License
12 stars 4 forks source link

Initial Layout for Rocket.Chat Flutter SDK #1

Closed yatendra2001 closed 1 year ago

yatendra2001 commented 1 year ago

Monorepo Approach

  1. Add a README file to the repository to provide an overview of the project, including its architecture, contribution guide, and desired skills. Keep adding more instructions as we move.
  2. Create a packages directory within the repository to contain different packages and modules.
  3. Create sub-directories within the packages directory to contain the following:
  1. Add a LICENSE file to the repository to specify the licensing terms for the project. (already done ✅)
  2. Add documentation to the repository to provide instructions on how to use the SDK, Core engine, and sample applications.
  3. Create issues and milestones to track progress and manage tasks.

Sample Package Structure

This structure is highly inspired by Stream Chat packages as they are currently being used by a lot of people in the flutter community.

I created a demo app, so an example app layout can be found here

I will start working on laying out the repo once you approve @Sing-Li

Sing-Li commented 1 year ago

Thanks @yatendra2001 ! That is very thoughtful and extensive.

I'd like to see a little modification to the proposed naming scheme.

The two items I see as being important

  1. "Chat Component" - EmbeddedChat equivalent component - ready to be easily "dropped" into existing Flutter apps
  2. "API" - API layer Flutter binding for anyone wanting to access Rocket.Chat natively to build their own messaging experiences (your "Core" above)

(of course, 1 can be built upon 2 - but they do not need to (should not) evolve in locked steps)

I think in the subdirectoies of each of the projects - it is important to show the very different build, bundle, test, distribution, and CI workflows required

I do think that a pure Dart language level binding is out of the scope of this project (perhaps for Rocket.Chat.Dart.SDK instead) at this time; since Flutter level implementation will have many platform specific nuances that can get into the way of such attempts.

yatendra2001 commented 1 year ago

Thanks, @Sing-Li for the feedback.

The naming convention does make a lot of sense. So we can create 2 flutter packages Rocket_Chat_Component and Rocket_Chat_API. Right?

Yesssss, CI and CD are much required in order to build a robust package. Need to define unit tests, integration tests and widget tests according to the package.

I do think that a pure Dart language level binding is out of the scope of this project (perhaps for Rocket.Chat.Dart.SDK instead) at this time; since Flutter level implementation will have many platform-specific nuances that can get into the way of such attempts. ^ We can consider the above package as a dart client that will be used by rocket_chat_component and rocket_chat_api. Otherwise, we have to define the client separately for each package.

Also, I forgot to ask, we might need to build some sample apps as well for users, so should we keep them under this repo or make another under rocket chat?

Let me know if you think it's the correct way to move forward so that I can work on laying out the repo @Sing-Li

Sing-Li commented 1 year ago

The naming convention does make a lot of sense. So we can create 2 flutter packages Rocket_Chat_Component and Rocket_Chat_API. Right?

How about Rocket_Chat_EmbeddedChat_Component and Rocket_Chat_API ?

Yesssss, CI and CD are much required in order to build a robust package. Need to define unit tests, integration tests and widget tests according to the package.

Please show the new proposed directory structure, in the next reply, including:

  1. .github/workflows directories for associated Github Actions for CI - that leads to a dummy build/deploy of a skeleton artifact

  2. test and unit-test directories and dummy test skeleton

  3. changed naming convention as per above

    We can consider the above package as a dart client that will be used by rocket_chat_component and rocket_chat_api. Otherwise, we have to define the client separately for each package.

    I see what you mean. But I am really not certain that separation can be made at this level (given that there will be many platform specific tweaks that the Flutter layer above will demand).

Take a simple example -- if this layer is NOT created for Flutter only, then it should use Linux network and IO routines directly all the time. But since it is - it will need to use the platform specific networking facility. This case alone will make this layer rather useless as a generic Dart client - unless you rig it with a lot of conditionals during the compilation/build stage.

A pure Dart binding/SDK should allow me to create CLI clients on the minimal Linux distro such as Alpine without any UI/system encumbrances and baggage (exerted by Flutter).

Also, I forgot to ask, we might need to build some sample apps as well for users, so should we keep them under this repo or make another under rocket chat?

Yes - so for Rocket_Chat_EmbeddedChat_Component it should be existing (low complexity) Flutter App that just embed the component. We can have it in a CONTRIB or sample directory within that sub repo

And for Rocket_Chat_API it should be very simple API call and usage examples, many of them covering the entire exposed API individually and in logical groupings. We can have it in a CONTRIB or sample directory within that sub repo.

@yatendra2001 Thanks!

yatendra2001 commented 1 year ago

Sure @Sing-Li , Here's the updated layout:

- Rocket_Chat_FlutterSDK
    - .gitignore
    - README.md
    - LICENSE
    - .github/
        - workflows/
            - ci.yml
    - packages/
        - rocket_chat_embeddedchat_component/
            - lib/
                - models/
                - bloc/
                - utils/
                - widgets/
                - client.dart
                - connection_status.dart
                - ...
            - pubspec.yaml       
            - sample_app 
            - test/
                - unit_tests/
                    - ...
                - integration_tests/
                    - ...
                - widget_tests/
                    - ...

        - rocket_chat_api/
            - lib/
                - src/
                    - api/
                    - models/
                    - ...
                - extensions/
                - utils/
                - client.dart
                - connection_status.dart
                - ...
            - pubspec.yaml
            - sample_app
            - test/
                - unit_tests/
                    - ...
                - integration_tests/
                    - ...
                - widget_tests/
                    - ...

And a sample app might look like this:

- sample_app/
    - lib/
        - main.dart
    - pubspec.yaml
    - test/
        - unit_tests/
            - ...
        - integration_tests/
            - ...
        - widget_tests/
            - ...
    - android/
    - ios/
    - windows/
    - linux/
    - macos/

Here's a brief explanation of the changes made to the layout:

  1. .github/workflows/: Contains the GitHub Actions workflow files.
    • ci.yml: A GitHub Actions workflow file for continuous integration that builds and tests the code.
  2. test/ directories are added inside each package (rocket_chat_embeddedchat_component and rocket_chat_api)
    • unit_tests/: Contains unit tests for each package.
    • integration_tests/: Contains integration tests for each package.
    • widget_tests/: Contains widget tests for each package.

Here are dummy skeletons for each type of tests:

  1. Unit test skeleton:
import 'package:flutter_test/flutter_test.dart';
import 'package:rocket_chat_api/rocket_chat_api.dart'; // Replace with package import

void main() {
  group('Dummy Unit Test', () {
    test('Description of the test case', () {
      // Arrange: Set up the test variables, mock objects, and/or test inputs

      // Act: Perform the action or function you want to test

      // Assert: Check if the expected output/result matches the actual output/result
      expect(actualResult, expectedResult);
    });
  });
}
  1. Widget test skeleton:
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:rocket_chat_embeddedchat_component/widgets/some_widget.dart'; // Replace with widget import

void main() {
  group('Dummy Widget Test', () {
    testWidgets('Description of the test case', (WidgetTester tester) async {
      // Arrange: Create the widget you want to test
      final widget = SomeWidget(); // Replace with widget

      // Act: Render the widget in the test environment
      await tester.pumpWidget(MaterialApp(home: Scaffold(body: widget)));

      // Assert: Check if the widget is present and/or behaves as expected
      expect(find.byType(SomeWidget), findsOneWidget); // Replace with assertions
    });
  });
}
  1. Integration test skeleton
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:example/main.dart'; // Replace with example app import

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('Dummy Integration Test', () {
    testWidgets('Description of the test case', (WidgetTester tester) async {
      // Arrange: Set up the test environment by rendering the app
      await tester.pumpWidget(MyApp()); // Replace with app widget

      // Act: Perform actions or navigation within the app

      // Assert: Check if the app behaves as expected
      expect(find.text('Some Text'), findsOneWidget); // Replace with assertions
    });
  });
}

I have tried to build a standard github actions workflow as well:

name: Continuous Integration

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build_and_test:
    name: Build and Test
    runs-on: ubuntu-latest

    strategy:
      matrix:
        flutter: [stable]

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Setup Flutter
      uses: subosito/flutter-action@v1
      with:
        channel: ${{ matrix.flutter }}

    - name: Cache dependencies
      uses: actions/cache@v2
      with:
        path: |
          packages/rocket_chat_flutter/.dart_tool/package_config.json
          packages/rocket_chat_api/.dart_tool/package_config.json
          example/.dart_tool/package_config.json
        key: ${{ runner.os }}-flutter-${{ matrix.flutter }}-${{ hashFiles('**/pubspec.lock') }}
        restore-keys: |
          ${{ runner.os }}-flutter-${{ matrix.flutter }}-

    - name: Get dependencies
      run: flutter pub get
      working-directory: packages/rocket_chat_api

    - name: Get dependencies
      run: flutter pub get
      working-directory: packages/rocket_chat_embeddedchat_component

    - name: Get dependencies
      run: flutter pub get
      working-directory: example

    - name: Run tests
      run: flutter test
      working-directory: packages/rocket_chat_api

    - name: Run tests
      run: flutter test
      working-directory: packages/rocket_chat_embeddedchat_component

    - name: Run tests
      run: flutter test
      working-directory: example

    - name: Analyze code
      run: flutter analyze
      working-directory: packages/rocket_chat_api

    - name: Analyze code
      run: flutter analyze
      working-directory: packages/rocket_chat_embeddedchat_component

    - name: Analyze code
      run: flutter analyze
      working-directory: example

    - name: Build example app
      run: flutter build apk
      working-directory: example

Note: The layout and continuous integration might evolve over time as we encounter further challenges and solutions.

Thanks!!!

Sing-Li commented 1 year ago

Awesome. Please just make sure that you can successfully CI build to binary - the two main artifacts:

  1. rocket_chat_embeddedchat_component
  2. rocket_chat_api

Then I think this is good to go. Looking forward to the first PR! Thanks.