├── .github
├── ISSUE_TEMPLATE
│ ├── ---bug-report.md
│ ├── ---feature-request.md
│ ├── ---questions---help.md
│ └── config.yml
├── pull_request_template.md
└── workflows
│ ├── deploy-pages.yaml
│ └── flutter-analyze.yaml
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── CNAME
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── doc
├── .gitignore
├── README.md
├── babel.config.js
├── docs
│ ├── guides
│ │ ├── supabase-security-rls.md
│ │ ├── supabase-usage.md
│ │ ├── supabse-indexes.md
│ │ ├── supabse-trigges.md
│ │ └── supabse-views.md
│ └── introduction
│ │ ├── supabase-overview.md
│ │ ├── supabase-package-installation.md
│ │ └── supabase-project-configuration.md
├── docusaurus.config.ts
├── package-lock.json
├── package.json
├── sidebars.ts
├── src
│ └── css
│ │ └── custom.css
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── favicon.ico
│ │ ├── flayer_chat_ui_screenshot.png
│ │ ├── logo.svg
│ │ ├── social-card.png
│ │ ├── supabase-disable-confirm-email.png
│ │ ├── supabase-project-credential.png
│ │ └── supabase-schema-exposure-setting.png
└── tsconfig.json
├── example
├── .gitignore
├── .metadata
├── README.md
├── analysis_options.yaml
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── untitled1
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ ├── flyer_logo.png
│ └── flyer_logo.svg
├── devtools_options.yaml
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ │ └── LaunchImage.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ └── README.md
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── lib
│ ├── main.dart
│ ├── src
│ │ ├── class
│ │ │ ├── message_status_ex.dart
│ │ │ └── user_ex.dart
│ │ ├── pages
│ │ │ ├── auth.dart
│ │ │ ├── home.dart
│ │ │ ├── room.dart
│ │ │ ├── rooms.dart
│ │ │ └── users.dart
│ │ ├── theme
│ │ │ └── color_schemes.dart
│ │ ├── util.dart
│ │ └── widgets
│ │ │ ├── room_tile.dart
│ │ │ └── user_tile.dart
│ └── supabase_options.dart
├── linux
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos
│ ├── .gitignore
│ ├── Flutter
│ │ ├── Flutter-Debug.xcconfig
│ │ └── Flutter-Release.xcconfig
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── app_icon_1024.png
│ │ │ │ ├── app_icon_128.png
│ │ │ │ ├── app_icon_16.png
│ │ │ │ ├── app_icon_256.png
│ │ │ │ ├── app_icon_32.png
│ │ │ │ ├── app_icon_512.png
│ │ │ │ └── app_icon_64.png
│ │ ├── Base.lproj
│ │ │ └── MainMenu.xib
│ │ ├── Configs
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── pubspec.yaml
├── utils
│ ├── prepare.ps1
│ ├── prepare.sh
│ └── sql
│ │ ├── 01_database_schema.sql
│ │ ├── 02_database_trigger.sql
│ │ ├── 03_database_policy.sql
│ │ ├── 04_storage.sql
│ │ ├── 05_database_view.sql
│ │ └── 99_database_schema_permission.sql
├── web
│ ├── favicon.png
│ ├── icons
│ │ ├── Icon-192.png
│ │ ├── Icon-512.png
│ │ ├── Icon-maskable-192.png
│ │ └── Icon-maskable-512.png
│ ├── index.html
│ └── manifest.json
└── windows
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
│ └── runner
│ ├── CMakeLists.txt
│ ├── Runner.rc
│ ├── flutter_window.cpp
│ ├── flutter_window.h
│ ├── main.cpp
│ ├── resource.h
│ ├── resources
│ └── app_icon.ico
│ ├── runner.exe.manifest
│ ├── utils.cpp
│ ├── utils.h
│ ├── win32_window.cpp
│ └── win32_window.h
├── lib
├── flutter_supabase_chat_core.dart
└── src
│ ├── class
│ ├── supabase_chat_controller.dart
│ ├── supabase_chat_core.dart
│ ├── supabase_chat_core_config.dart
│ ├── upload_asset_result.dart
│ └── user_online_status.dart
│ ├── util.dart
│ └── widgets
│ ├── user_online_status.dart
│ ├── user_status_detector
│ ├── other_platform.dart
│ ├── platforms_widgets_binding.dart
│ ├── web_platform.dart
│ └── widgets_binding.dart
│ └── user_status_observer.dart
└── pubspec.yaml
/.github/ISSUE_TEMPLATE/---bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41B Bug report"
3 | about: Something isn't working? Create a report to help us improve Flyer Chat.
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 |
22 |
23 | # General
24 |
25 | ## What bug do you experience? 🐞
26 | Provide a clear and concise description of what the bug is.
27 |
28 | ## How can it be reproduced? 🤔
29 | A few steps to define where does the bug occur.
30 | Step 1. ...
31 | Step 2. ... etc.
32 |
33 | ## What behavior is expected? 💡
34 | A clear and concise description of what you expected to happen.
35 |
36 |
37 |
38 | # Extras
39 |
40 | ## Screenshots or videos 📸
41 | If applicable, add screenshots or videos to help explain your problem.
42 |
43 | ## Code snippets 📝
44 | If applicable, add code samples to help explain your problem.
45 |
46 | ```dart
47 | // Your snippet here...
48 | ```
49 |
50 |
51 |
52 | # Environment info
53 |
54 | Please specify the flutter, flutter_supabase_chat_core versions.
55 |
56 | flutter: ...
57 | flutter_supabase_chat_core: ...
58 |
59 | `flutter doctor -v` output 👇
60 |
61 | ```sh
62 | ```
63 |
64 |
65 |
66 | # Platform
67 |
68 | Device (e.g. Android emulator, iOS simulator, Samsung Galaxy S21): ...
69 |
70 | OS version (e.g. iOS 14.5, Android 11): ...
71 |
72 |
73 |
74 | # Additional context
75 |
76 | Add any other context about the problem here.
77 |
78 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "⚡️ Feature request"
3 | about: Suggest an idea to help make Flyer Chat even better!
4 | title: ''
5 | labels: feature
6 | assignees: ''
7 |
8 | ---
9 |
10 |
15 |
16 | ## Is your feature request related to a problem?
17 | A clear and concise description of what the problem is or why we should process it.
18 |
19 | ## What solution would you suggest?
20 | A clear and concise description of what you want to happen. How would it solve the problem of yours?
21 |
22 | ## Is there any additional solution to that?
23 | A clear and concise description of any alternative solutions or features you've considered.
24 |
25 | ## Extras
26 | **Screenshots or videos 📸**
27 | If applicable, add screenshots or videos to help explain your feature.
28 |
29 | **Code snippets 📝**
30 | If applicable, add code samples to help explain your feature.
31 |
32 | ```dart
33 | // Your snippet here...
34 | ```
35 |
36 | ## Related issues/PRs
37 | Let us know if this is related to any issue/pull request.
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---questions---help.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F914 Questions & help"
3 | about: " Use this if there is something not clear about the code or documentation."
4 | title: ''
5 | labels: question
6 | assignees: ''
7 |
8 | ---
9 |
10 |
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Link preview
4 | url: https://github.com/flyerhq/flutter_link_previewer/issues/new
5 | about: Use this to report link preview issues.
6 | - name: Chat UI
7 | url: https://github.com/flyerhq/flutter_chat_ui/issues/new/choose
8 | about: Use this to report chat UI issues.
9 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
12 |
13 | ### What does it do?
14 |
15 | Describe the technical changes you did.
16 |
17 | ### Why is it needed?
18 |
19 | Describe the issue you are solving.
20 |
21 | ### How to test it?
22 |
23 | Provide information about the environment and the path to verify the behavior.
24 |
25 | ### Related issues/PRs
26 |
27 | Let us know if this is related to any issue/pull request.
--------------------------------------------------------------------------------
/.github/workflows/deploy-pages.yaml:
--------------------------------------------------------------------------------
1 | name: Deploy GitHub pages
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v2
13 |
14 | - name: Setup Node.js
15 | uses: actions/setup-node@v4
16 | with:
17 | node-version: 20
18 |
19 | - name: Install dependencies
20 | run: npm install
21 | working-directory: doc
22 |
23 | - name: Build site
24 | run: npm run build
25 | working-directory: doc
26 |
27 | - name: Add CNAME file
28 | run: cp ./CNAME ./doc/build/CNAME
29 |
30 | - name: Deploy to GitHub Pages
31 | uses: peaceiris/actions-gh-pages@v3
32 | with:
33 | github_token: ${{ secrets.GITHUB_TOKEN }}
34 | publish_dir: ./doc/build
--------------------------------------------------------------------------------
/.github/workflows/flutter-analyze.yaml:
--------------------------------------------------------------------------------
1 | name: Flutter analyze
2 |
3 | on:
4 | pull_request:
5 | branches: [main, dev]
6 |
7 | jobs:
8 | flutter-analyze:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 |
13 | - name: Setup Flutter environment
14 | uses: subosito/flutter-action@v2
15 | with:
16 | channel: 'stable'
17 |
18 | - name: Install dependencies
19 | run: flutter pub get
20 |
21 | - name: Analyze formatting
22 | run: dart format . --set-exit-if-changed
23 |
24 | - name: Analyze project source
25 | run: flutter analyze --no-pub
26 |
27 | - name: Install pana
28 | run: dart pub global activate pana
29 |
30 | - name: Analyze project source with pana
31 | run: pana
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .classpath
21 | .project
22 | .settings/
23 | .vscode/
24 |
25 | # Flutter repo-specific
26 | /bin/cache/
27 | /bin/internal/bootstrap.bat
28 | /bin/internal/bootstrap.sh
29 | /bin/mingit/
30 | /dev/benchmarks/mega_gallery/
31 | /dev/bots/.recipe_deps
32 | /dev/bots/android_tools/
33 | /dev/devicelab/ABresults*.json
34 | /dev/docs/doc/
35 | /dev/docs/flutter.docs.zip
36 | /dev/docs/lib/
37 | /dev/docs/pubspec.yaml
38 | /dev/integration_tests/**/xcuserdata
39 | /dev/integration_tests/**/Pods
40 | /packages/flutter/coverage/
41 | version
42 | analysis_benchmark.json
43 |
44 | # packages file containing multi-root paths
45 | .packages.generated
46 |
47 | # Flutter/Dart/Pub related
48 | **/doc/api/
49 | .dart_tool/
50 | .flutter-plugins
51 | .flutter-plugins-dependencies
52 | **/generated_plugin_registrant.dart
53 | .packages
54 | .pub-cache/
55 | .pub/
56 | build/
57 | flutter_*.png
58 | linked_*.ds
59 | unlinked.ds
60 | unlinked_spec.ds
61 |
62 | # Android related
63 | **/android/**/gradle-wrapper.jar
64 | **/android/.gradle
65 | **/android/captures/
66 | **/android/gradlew
67 | **/android/gradlew.bat
68 | **/android/local.properties
69 | **/android/**/GeneratedPluginRegistrant.java
70 | **/android/key.properties
71 | *.jks
72 |
73 | # iOS/XCode related
74 | **/ios/**/*.mode1v3
75 | **/ios/**/*.mode2v3
76 | **/ios/**/*.moved-aside
77 | **/ios/**/*.pbxuser
78 | **/ios/**/*.perspectivev3
79 | **/ios/**/*sync/
80 | **/ios/**/.sconsign.dblite
81 | **/ios/**/.tags*
82 | **/ios/**/.vagrant/
83 | **/ios/**/DerivedData/
84 | **/ios/**/Icon?
85 | **/ios/**/Pods/
86 | **/ios/**/.symlinks/
87 | **/ios/**/profile
88 | **/ios/**/xcuserdata
89 | **/ios/.generated/
90 | **/ios/Flutter/.last_build_id
91 | **/ios/Flutter/App.framework
92 | **/ios/Flutter/Flutter.framework
93 | **/ios/Flutter/Flutter.podspec
94 | **/ios/Flutter/Generated.xcconfig
95 | **/ios/Flutter/ephemeral
96 | **/ios/Flutter/app.flx
97 | **/ios/Flutter/app.zip
98 | **/ios/Flutter/flutter_assets/
99 | **/ios/Flutter/flutter_export_environment.sh
100 | **/ios/ServiceDefinitions.json
101 | **/ios/Runner/GeneratedPluginRegistrant.*
102 |
103 | # macOS
104 | **/macos/Flutter/GeneratedPluginRegistrant.swift
105 |
106 | # Coverage
107 | coverage/
108 |
109 | # Symbols
110 | app.*.symbols
111 |
112 | # Exceptions to above rules.
113 | !**/ios/**/default.mode1v3
114 | !**/ios/**/default.mode2v3
115 | !**/ios/**/default.pbxuser
116 | !**/ios/**/default.perspectivev3
117 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
118 | !/dev/ci/**/Gemfile.lock
119 | !**/ios/**/Podfile.lock
120 |
121 | # Test scripts files
122 | test-scripts
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [1.5.0] - 2025-02-06
2 | #### [@rickypid](https://github.com/rickypid)
3 |
4 | ### Dependencies
5 |
6 | * Upgrade supabase_flutter: ^2.8.3
7 |
8 | ## [1.4.3] - 2024-12-26
9 | #### [@rickypid](https://github.com/rickypid)
10 | #### [@lazy-geek](https://github.com/lazy-geek)
11 |
12 | ℹ️ ℹ️ **Recommended scheme migration** ℹ️ ℹ️
13 |
14 | Improvement documentations.
15 |
16 | ### Fixed
17 |
18 | * Fixed #25 Update chats.update_last_messages trigger to make sure it is only called for actual last message in case of update
19 | * Fixed #27 Error in room or message deletion query, a `limit(1)` was incorrectly applied
20 |
21 | ## [1.4.2] - 2024-11-30
22 | #### [@rickypid](https://github.com/rickypid)
23 |
24 | ### Dependencies
25 |
26 | * Upgrade mine: '>=1.0.2 <3.0.0'
27 |
28 | ## [1.4.1] - 2024-11-21
29 | #### [@rickypid](https://github.com/rickypid)
30 | #### [@Parfyonator](https://github.com/Parfyonator)
31 |
32 | ### Fixed
33 |
34 | * Fixed #20 Chat creator role is null instead of admin
35 |
36 | ## [1.4.0] - 2024-11-21
37 | #### [@rickypid](https://github.com/rickypid)
38 |
39 | ⚠️⚠️ **Need schema migration** ⚠️⚠️
40 |
41 | ### Improvements
42 |
43 | * Now when we get the rooms the `rooms_l` view is used so that we can get all the information without having to do multiple queries
44 |
45 | ### Fixed
46 |
47 | * Fixed #20 Chat creator role is null instead of admin
48 | * Fixed online user status realtime subscription
49 |
50 | ## [1.3.2] - 2024-11-13
51 | #### [@rickypid](https://github.com/rickypid)
52 |
53 | Improve documentations
54 |
55 | ### Fixed
56 |
57 | * Fixed schema `chats` permission after view creation
58 |
59 | ## [1.3.1] - 2024-11-12
60 | #### [@rickypid](https://github.com/rickypid)
61 |
62 | ### Fixed
63 |
64 | * Fixed `updateRoomList` sorting
65 |
66 | ## [1.3.0] - 2024-11-04
67 | #### [@rickypid](https://github.com/rickypid)
68 |
69 | ⚠️⚠️ **Some Breaking Changes** ⚠️⚠️
70 |
71 | ### New features
72 |
73 | * Added Rooms list pagination and searchable
74 |
75 | ### Fixed
76 |
77 | * Security fix on RLS helper functions
78 |
79 | ## [1.2.0] - 2024-10-31
80 | #### [@rickypid](https://github.com/rickypid)
81 |
82 | ⚠️⚠️ **Some Breaking Changes** ⚠️⚠️
83 |
84 | ### New features
85 |
86 | * Added Users list pagination and searchable
87 | * Added Users typing status
88 |
89 | ### Fixed
90 |
91 | * Fix database index e security fix on function
92 |
93 | ## [1.1.0] - 2024-08-30
94 | #### [@danbeech](https://github.com/danbeech)
95 | #### [@rickypid](https://github.com/rickypid)
96 |
97 | ### Fixed
98 |
99 | * Fixed update room call
100 | * Fixed Dart SDK version for Flutter 3.22.x (#9)
101 | * Updated dependencies
102 |
103 | ## [1.0.0] - 2024-06-19
104 | #### [@rickypid](https://github.com/rickypid)
105 |
106 | ### Fixed
107 |
108 | * Fixed schema migration (#3)
109 | * Fixed example theme variables, now support Flutter > 3.22.x
110 |
111 | ## [0.10.0] - 2024-04-04
112 | #### [@rickypid](https://github.com/rickypid)
113 |
114 | ### Features
115 |
116 | * Added user online status support
117 | * Added room messages pagination, now it's possible load messages on chat scrolling
118 | * Added `SupabaseChatController`
119 |
120 | ### Widgets
121 |
122 | * Added `UserOnlineStateObserver` widget
123 | * Added `UserOnlineStatusWidget` widget
124 |
125 | ### Dependencies
126 |
127 | * Removed `dio` dependency
128 | * Upgraded `supabase_flutter` to `^2.4.0`
129 |
130 | ## [0.9.0] - 2024-03-11
131 | #### [@rickypid](https://github.com/rickypid)
132 |
133 | * Improved documentation
134 | * Fixed RSL on chats schema
135 | * Add files download support
136 | * Test on Android device
137 | * Renamed `SupabseChatCore` to `SupabaseChatCore` 😅 (typo)
138 | * Added logic to change status in read messages
139 | * Dependencies updated
140 |
141 | ## [0.0.2] - 2024-02-12
142 | #### [@rickypid](https://github.com/rickypid)
143 |
144 | * Improved documentation and fixed GitHub Pages CI
145 |
146 | ## [0.0.1] - 2024-02-09
147 | #### [@rickypid](https://github.com/rickypid)
148 |
149 | * Initial release
150 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | flutter-supabase-chat-core.insideapp.it
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Flyer Chat
2 |
3 | Thank you for your interest in contributing to Flyer Chat! Our vision is to create an easy-to-use chat experience for any application and while we can't have everything right from the start, we can build it together! If you plan to implement a feature and open a pull request, make sure you don't spend a lot of time on it, otherwise open an issue so we can discuss bigger stuff.
4 |
5 | The [Open Source Guides](https://opensource.guide) website has a collection of resources for individuals, communities, and companies who want to learn how to run and contribute to an open-source project. Contributors and people new to open source alike will find the following guides especially useful:
6 |
7 | * [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
8 | * [Building Welcoming Communities](https://opensource.guide/building-community/)
9 |
10 | ## Helping with Documentation
11 |
12 | We use [Docusaurus](https://docusaurus.io) to build our documentation which is located in the [doc](https://github.com/insideapp-srl/flutter_supabase_chat_core/tree/main/doc) folder. If you are adding new functionality or introducing a behavior change, we will ask you to update the documentation to reflect your changes.
13 |
14 | ## Contributing Code
15 |
16 | Code-level contributions to Flyer Chat generally come in the form of pull requests. These are done by forking the repo and making changes locally. Directly in the repo, there is the [example](https://github.com/insideapp-srl/flutter_supabase_chat_core/tree/main/example) project that you can install on your device (or simulators) and use to test the changes you're making to Flyer Chat sources.
17 |
18 | [Here](https://opensource.guide/how-to-contribute/#opening-a-pull-request) you can read how to open a pull request.
19 |
20 | ## Community Contributions
21 |
22 | Contributions to Flyer Chat are not limited to GitHub. You can help others by sharing your experience using Flyer Chat, whether that is through blog posts, presenting talks at conferences, or simply sharing your thoughts on social media.
23 |
24 | ## License
25 |
26 | By contributing to Flyer Chat, you agree that your contributions will be licensed under its [Apache License, Version 2.0](LICENSE).
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 | - always_declare_return_types
6 | - avoid_unused_constructor_parameters
7 | - directives_ordering
8 | - omit_local_variable_types
9 | - prefer_expression_function_bodies
10 | - prefer_final_fields
11 | - prefer_final_locals
12 | - prefer_relative_imports
13 | - prefer_single_quotes
14 | - sized_box_for_whitespace
15 | - sort_child_properties_last
16 | - sort_pub_dependencies
17 | - type_annotate_public_apis
18 | - unawaited_futures
19 | - use_named_constants
20 | - use_super_parameters
21 | - require_trailing_commas
22 |
23 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4 |
5 | ### Installation
6 |
7 | ```
8 | $ yarn
9 | ```
10 |
11 | ### Local Development
12 |
13 | ```
14 | $ yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ### Build
20 |
21 | ```
22 | $ yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ### Deployment
28 |
29 | Using SSH:
30 |
31 | ```
32 | $ USE_SSH=true yarn deploy
33 | ```
34 |
35 | Not using SSH:
36 |
37 | ```
38 | $ GIT_USER= yarn deploy
39 | ```
40 |
41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
42 |
--------------------------------------------------------------------------------
/doc/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/doc/docs/guides/supabse-indexes.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-indexes
3 | title: Database Indexes
4 | ---
5 |
6 | ## `chats.messages` indexes
7 |
8 | These indexes are added to improve the performance of foreign keys in database tables:
9 |
10 | ```sql
11 | CREATE INDEX ON "chats"."messages" USING btree ("authorId");
12 | CREATE INDEX ON "chats"."messages" USING btree ("roomId");
13 | ```
14 |
--------------------------------------------------------------------------------
/doc/docs/guides/supabse-trigges.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-triggers
3 | title: Database Triggers
4 | ---
5 |
6 | ## Update room last message
7 |
8 | This is a trigger that sets room's `lastMessages` to the most recent message sent once recieved in Supabase.
9 |
10 | ```sql
11 | CREATE OR REPLACE FUNCTION chats.update_last_messages()
12 | RETURNS TRIGGER
13 | SET search_path = ''
14 | AS $$
15 | DECLARE
16 | ts_in_milliseconds bigint;
17 | BEGIN
18 | SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds;
19 | UPDATE chats.rooms
20 | SET "updatedAt" = ts_in_milliseconds,
21 | "lastMessages" = jsonb_build_array(NEW)
22 | WHERE id = NEW."roomId";
23 | RETURN NEW;
24 | END;
25 | $$ LANGUAGE plpgsql;
26 |
27 | drop trigger if exists update_last_messages_trigger on chats.messages;
28 | CREATE TRIGGER update_last_messages_trigger
29 | AFTER INSERT OR UPDATE ON chats.messages
30 | FOR EACH ROW
31 | EXECUTE FUNCTION chats.update_last_messages();
32 | ```
33 |
34 | ## Set message status to sent
35 |
36 | "This trigger, on the other hand, is responsible for setting the message status to `sent` when it is added to the `messages` table:
37 |
38 | ```sql
39 | CREATE OR REPLACE FUNCTION chats.set_message_status_to_sent()
40 | RETURNS TRIGGER
41 | SET search_path = ''
42 | AS $$
43 | BEGIN
44 | NEW.status := 'sent';
45 | RETURN NEW;
46 | END;
47 | $$ LANGUAGE plpgsql;
48 |
49 | drop trigger if exists update_status_before_insert on chats.messages;
50 | CREATE TRIGGER update_status_before_insert
51 | BEFORE INSERT ON chats.messages
52 | FOR EACH ROW EXECUTE FUNCTION chats.set_message_status_to_sent();
53 | ```
54 |
55 | ## Handle new user from `auth.users`
56 |
57 | "This trigger, is responsible for replicate `auth.users` table rows in `chats.users` table, this is to avoid exposing user data :
58 |
59 | ```sql
60 |
61 | CREATE OR REPLACE FUNCTION chats.handle_new_user()
62 | RETURNS trigger
63 | LANGUAGE 'plpgsql'
64 | COST 100
65 | VOLATILE NOT LEAKPROOF SECURITY DEFINER
66 | SET search_path=public
67 | SET search_path = ''
68 | AS $BODY$
69 | DECLARE
70 | ts_in_milliseconds bigint;
71 | BEGIN
72 | SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds;
73 | insert into chats.users (id, "createdAt", "updatedAt", "lastSeen")
74 | values (new.id, ts_in_milliseconds, ts_in_milliseconds, ts_in_milliseconds);
75 | return new;
76 | end;
77 | $BODY$;
78 |
79 | drop trigger if exists on_auth_user_created on auth.users;
80 | create trigger on_auth_user_created
81 | after insert on auth.users
82 | for each row execute procedure chats.handle_new_user();
83 |
84 | ```
--------------------------------------------------------------------------------
/doc/docs/guides/supabse-views.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-views
3 | title: Database Views
4 | ---
5 |
6 | ## Rooms view
7 |
8 | This is a view of `rooms` table, this view allows you to obtain the name of the sender of the message dynamically in direct rooms, based on the logged-in user the name of the correspondent is displayed, it is also included the list of uses member objects.
9 |
10 | ```sql
11 | create or replace view chats.rooms_l
12 | with (security_invoker='on') as
13 | select r.id,
14 | r."imageUrl",
15 | r.metadata,
16 | case
17 | when r.type = 'direct' and auth.uid() is not null then
18 | (select coalesce(u."firstName", '') || ' ' || coalesce(u."lastName", '')
19 | from chats.users u
20 | where u.id = any (r."userIds")
21 | and u.id <> auth.uid()
22 | limit 1)
23 | else
24 | r.name
25 | end as name,
26 | r.type,
27 | r."userIds",
28 | r."lastMessages",
29 | r."userRoles",
30 | r."createdAt",
31 | r."updatedAt",
32 | (select jsonb_agg(to_jsonb(u))
33 | from chats.users u
34 | where u.id = any (r."userIds")) as users
35 | from chats.rooms r;
36 | ```
37 |
38 |
39 | ## Messages view
40 |
41 | This is a view of `messages` table, this view allows you to obtain the author user object and room object.
42 |
43 | ```sql
44 | create or replace view chats.messages_l
45 | with (security_invoker='on') as
46 | select m.id,
47 | m."createdAt",
48 | m.metadata,
49 | m.duration,
50 | m."mimeType",
51 | m.name,
52 | m."remoteId",
53 | m."repliedMessage",
54 | m."roomId",
55 | m."showStatus",
56 | m.size,
57 | m.status,
58 | m.type,
59 | m."updatedAt",
60 | m.uri,
61 | m."waveForm",
62 | m."isLoading",
63 | m.height,
64 | m.width,
65 | m."previewData",
66 | m."authorId",
67 | m.text,
68 | to_jsonb(u) as author,
69 | to_jsonb(r) as room
70 | from chats.messages m
71 | left join chats.users u on u.id = m."authorId"
72 | left join chats.rooms_l r on r.id = m."roomId";
73 | ```
--------------------------------------------------------------------------------
/doc/docs/introduction/supabase-overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-overview
3 | title: Overview
4 | slug: /
5 | ---
6 |
7 | Have you ever wanted to implement a chat in your application? Do you think it's difficult and complex?
8 |
9 | Try this, thanks to the magnificent [Supabase](https://supabase.com/) platform and the [Flutter Chat UI](https://pub.dev/packages/flutter_chat_ui) package, you can achieve it in just a few minutes and effortlessly.
10 |
11 | ---
12 |
13 | Flyer Chat is a platform for creating in-app chat experiences using Flutter or React Native. This is the documentation for Supabase BaaS implementation for Flutter.
14 |
15 | ## How it works?
16 |
17 | We use [Supabase](https://supabase.com/docs) as the backend. There we have three tables, `rooms`, `messages` and `users`. Let's break them down:
18 |
19 | * `rooms` table contains all conversations in your app. [Postgres Row Security Level](https://supabase.com/docs/guides/database/postgres/row-level-security) are responsible for showing only those rooms where the user's in. The room contains some metadata, a participants list and other room information.
20 | * `messages` table contains all messages in your app. [Postgres Row Security Level](https://supabase.com/docs/guides/database/postgres/row-level-security) are responsible for showing only those messages of the rooms where the user's in. The massage contains all message data.
21 | * `users` table contains users data, such as avatars and names. You can use this collection to render a list of users available for chat. This table is populate automatically by trigger.
22 |
23 | Both array of participant IDs in the `room` and rows in `users` tables use `User UID` from [Supabase Authentication](https://supabase.com/docs/guides/auth) as an ID, for easier navigation through the data. That means every user of the chat should be registered using Supabase's authentication module, but if your app doesn't use Supabase as an authentication provider, you still can register in Supabase by providing your `JWT` token, so you can have your backend working together with a chat on Supabase (in this case it will be necessary to remove the trigger that inserts users).
24 |
25 | [Postgres Triggers](https://supabase.com/docs/guides/database/postgres/triggers) can be used for setting message's statuses and for triggering push notifications. In this documentation, you will see an [example](../guides/supabse-trigges.md) of setting `delivered` message status.
26 |
27 | [Supabase Storage](https://supabase.com/docs/guides/storage) can be used as a storage provider for images and files.
28 |
29 | ## Motivation
30 |
31 | Ever estimated a simple chat for weeks of work? Didn't want to start because it is always the same boring work for an extended period of time? Was it moved to post MVP because of lack of time and resources? Were you left with a frustrated client, who couldn't understand why the thing that exists in almost every app takes that much time to implement?
32 |
33 | We are trying to solve all this by working on a Flyer Chat.
34 |
35 | You will say that there are libraries out there that will help create chats, but we are working on a more complete solution - very similar on completely different platforms like React Native and Flutter (we don't always work in just one) with an optional Supabase BaaS, since chat is not only UI. We are making this free and open-source so together we can create a product that works for everyone.
36 |
--------------------------------------------------------------------------------
/doc/docs/introduction/supabase-package-installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-package-installation
3 | title: Installation supabase_flutter
4 | ---
5 |
6 | This library depends on [supabase_flutter](https://pub.dev/packages/supabase_flutter). Follow the instructions there to configure the Supabase project and install [supabase_flutter](https://supabase.com/docs/reference/dart/introduction) plugin.
7 |
8 | Add `flutter_supabase_chat_core` to your package's `pubspec.yaml` file. Check current version on [pub.dev](https://pub.dev/packages/flutter_supabase_chat_core/install).
--------------------------------------------------------------------------------
/doc/docs/introduction/supabase-project-configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: supabase-project-configuration
3 | title: Supabase project preparation
4 | ---
5 |
6 | ### Create a Supabase project
7 |
8 | 1. Install Supabase CLI: [Official documentation](https://supabase.com/docs/guides/cli/getting-started)
9 | 2. Open your bash
10 | 3. Login with Supabase:
11 |
12 | ```bash
13 | supabase login
14 | ```
15 |
16 | 4. Create new project (For example `demo-chat`):
17 |
18 | ```bash
19 | supabase projects create demo-chat
20 | ```
21 |
22 | 5. Select your organization
23 | 6. Select an region
24 | 7. Insert a secure password for new Postgres database (Save this in a secure location)
25 | 8. Obtain your `REFERENCE ID` (After command select your project, for example `demo-chat`):
26 |
27 | ```bash
28 | supabase projects list
29 | ```
30 |
31 | 9. Obtain your `anon` key (After command select your project, for example `demo-chat`):
32 |
33 | ```bash
34 | supabase projects api-keys
35 | ```
36 | 10. Edit `example project` file `example/lib/supabase_options.dart`, insert your project `{{your_project_reference_id}}` and `{{supabase_anon_key}}`
37 |
38 | #### Prepare Supabase project
39 |
40 | Inside the example project (`example/utils`) there is a script, running the latter will automatically configure the Supabase project, creating tables, security rules, buckets and everything that is necessary for the example project to function.
41 |
42 | In order to run the script you need to be aware of the following information about your Supabase project:
43 |
44 | - `host` : Project host
45 | - `port` : Database port
46 | - `database` : Database name
47 | - `user` : Database user
48 | - `password` : Database password
49 |
50 | This information, with the exception of the password which is provided only during the creation of the database (if necessary, you can use the password reset function of your database to obtain it), can be found very easily from the Dashboard of your Supabase project:
51 |
52 | 
53 |
54 | #### Running prepare script
55 |
56 | Below are the commands for running the scripts (During execution you will be asked for the password for your database user):
57 |
58 | > Required `psql` installed -> [Official documentation](https://www.postgresql.org/download/)
59 |
60 | #### Linux
61 |
62 | ```bash
63 | cd ./example/utils/
64 | ./prepare.sh -h "your-postgres-host" -p your-postgres-port -d "your-postgres-database-name" -U "your-postgres-user"
65 | ```
66 |
67 | #### Windows
68 |
69 | ```powershell
70 | cd .\example\utils\
71 | .\prepare.ps1 -hostname "your-postgres-host" -port your-postgres-port -database "your-postgres-database-name" -user "your-postgres-user"
72 | ```
73 |
74 |
75 | after running the database preparation script. you need to change the database schema exposure setting by adding the `chats` schema (from the supabase dashboard):
76 |
77 | 
78 |
79 | Optional (**Only for test**): Disable email verification and save the configuration (To speed up testing and allow user registration in just one click, it is advisable to disable mailbox verification):
80 |
81 | 
82 |
83 | Read our [documentation](https://flutter-supabase-chat-core.insideapp.it) or see the [example](https://github.com/insideapp-srl/flutter_supabase_chat_core/tree/main/example) project. To run the example project you need to have your own [Supabase](https://supabase.com/dashboard/projects) project and then follow [Add Supabase to your Flutter app](https://supabase.com/docs/reference/dart/initializing), override `example/lib/supabase_options.dart`, don't commit it though 😉
84 |
85 | After all of this is done you will need to register a couple of users and the example app will automatically suggest email and password on the register screen, default password is `Qawsed1-`. To set up [Supabase Security Rules](https://supabase.com/docs/guides/database/postgres/row-level-security) so users can see only the data they should see, continue with our [documentation](https://flutter-supabase-chat-core.insideapp.it/).
86 |
--------------------------------------------------------------------------------
/doc/docusaurus.config.ts:
--------------------------------------------------------------------------------
1 | import {themes as prismThemes} from 'prism-react-renderer';
2 | import type {Config} from '@docusaurus/types';
3 | import type * as Preset from '@docusaurus/preset-classic';
4 |
5 | const config: Config = {
6 | title: 'Flutter Supabase Chat Core',
7 | tagline: 'Dinosaurs are cool',
8 | favicon: 'img/favicon.ico',
9 |
10 | // Set the production url of your site here
11 | url: 'https://flutter-supabase-chat-core.insideapp.it',
12 | // Set the // pathname under which your site is served
13 | // For GitHub pages deployment, it is often '//'
14 | baseUrl: '/',
15 |
16 | // GitHub pages deployment config.
17 | // If you aren't using GitHub pages, you don't need these.
18 | organizationName: 'insideapp-srl', // Usually your GitHub org/user name.
19 | projectName: 'flutter_supabase_chat_core', // Usually your repo name.
20 |
21 | onBrokenLinks: 'throw',
22 | onBrokenMarkdownLinks: 'warn',
23 |
24 | // Even if you don't use internationalization, you can use this field to set
25 | // useful metadata like html lang. For example, if your site is Chinese, you
26 | // may want to replace "en" with "zh-Hans".
27 | i18n: {
28 | defaultLocale: 'en',
29 | locales: ['en'],
30 | },
31 | presets: [
32 | [
33 | 'classic',
34 | {
35 | docs: {
36 | sidebarPath: './sidebars.ts',
37 | editUrl:
38 | 'https://github.com/insideapp-srl/flutter_supabase_chat_core',
39 | routeBasePath: '/',
40 | },
41 |
42 | theme: {
43 | customCss: './src/css/custom.css',
44 | },
45 | blog: false,
46 | } satisfies Preset.Options,
47 | ],
48 | ],
49 |
50 | themeConfig: {
51 | // Replace with your project's social card
52 | image: 'img/social-card.png',
53 | colorMode: {
54 | defaultMode: 'dark',
55 | disableSwitch: false,
56 | respectPrefersColorScheme: false,
57 | },
58 | navbar: {
59 | title: 'Flutter Supabase Chat Core',
60 | logo: {
61 | alt: 'Flyer Chat Logo',
62 | src: 'img/logo.svg',
63 | },
64 | items: [
65 | {
66 | type: 'docSidebar',
67 | sidebarId: 'tutorialSidebar',
68 | position: 'left',
69 | label: 'Tutorial',
70 | },
71 | {to: 'https://docs.flyer.chat/flutter/chat-ui/', label: 'Chat UI', position: 'left'},
72 | {
73 | to: 'https://docs.flyer.chat/flutter/firebase/firebase-overview',
74 | label: 'Firebase Core',
75 | position: 'left'
76 | },
77 | {
78 | href: 'https://github.com/insideapp-srl/flutter_supabase_chat_core',
79 | label: 'GitHub',
80 | position: 'right',
81 | },
82 | ],
83 | },
84 | footer: {
85 | style: 'dark',
86 | links: [
87 | {
88 | title: 'Docs',
89 | items: [
90 | {
91 | label: 'How use',
92 | to: '/',
93 | },
94 | ],
95 | },
96 | {
97 | title: 'Community',
98 | items: [
99 | {
100 | label: 'Site',
101 | href: 'https://www.insideapp.it/',
102 | },
103 | {
104 | label: 'GitHub',
105 | href: 'https://github.com/insideapp-srl/flutter_supabase_chat_core',
106 | },
107 | ],
108 | },
109 | {
110 | title: 'More',
111 | items: [
112 | {
113 | label: 'Blog',
114 | to: 'https://blog.insideapp.it/',
115 | },
116 | ],
117 | },
118 | ],
119 | copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
120 | },
121 | prism: {
122 | theme: prismThemes.github,
123 | darkTheme: prismThemes.dracula,
124 | },
125 | } satisfies Preset.ThemeConfig,
126 | };
127 |
128 | export default config;
129 |
--------------------------------------------------------------------------------
/doc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flutter-supabase-chat-core",
3 | "version": "1.4.3",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids",
15 | "typecheck": "tsc"
16 | },
17 | "dependencies": {
18 | "@docusaurus/core": "3.6.3",
19 | "@docusaurus/preset-classic": "3.6.3",
20 | "@mdx-js/react": "^3.1.0",
21 | "clsx": "^2.1.1",
22 | "prism-react-renderer": "^2.4.1",
23 | "react": "^18.3.1",
24 | "react-dom": "^18.3.1"
25 | },
26 | "devDependencies": {
27 | "@docusaurus/module-type-aliases": "3.6.3",
28 | "@docusaurus/tsconfig": "3.6.3",
29 | "@docusaurus/types": "3.6.3",
30 | "typescript": "~5.7.2"
31 | },
32 | "browserslist": {
33 | "production": [
34 | ">0.5%",
35 | "not dead",
36 | "not op_mini all"
37 | ],
38 | "development": [
39 | "last 3 chrome version",
40 | "last 3 firefox version",
41 | "last 5 safari version"
42 | ]
43 | },
44 | "engines": {
45 | "node": ">=18.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/doc/sidebars.ts:
--------------------------------------------------------------------------------
1 | import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
2 |
3 | /**
4 | * Creating a sidebar enables you to:
5 | - create an ordered group of docs
6 | - render a sidebar for each doc of that group
7 | - provide next/previous navigation
8 |
9 | The sidebars can be generated from the filesystem, or explicitly defined here.
10 |
11 | Create as many sidebars as you want.
12 | */
13 | const sidebars: SidebarsConfig = {
14 | // By default, Docusaurus generates a sidebar from the docs folder structure
15 | //tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
16 |
17 | // But you can create a sidebar manually
18 |
19 | tutorialSidebar: [
20 | {
21 | type: 'category',
22 | label: 'Introduction',
23 | items: [
24 | 'introduction/supabase-overview',
25 | 'introduction/supabase-project-configuration',
26 | 'introduction/supabase-package-installation',
27 | ],
28 | },
29 | {
30 | type: 'category',
31 | label: 'Guides',
32 | items: [
33 | 'guides/supabase-usage',
34 | 'guides/supabase-security',
35 | 'guides/supabase-triggers',
36 | 'guides/supabase-views',
37 | 'guides/supabase-indexes',
38 | ],
39 | },
40 | ],
41 |
42 | };
43 |
44 | export default sidebars;
45 |
--------------------------------------------------------------------------------
/doc/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #2e8555;
10 | --ifm-color-primary-dark: #29784c;
11 | --ifm-color-primary-darker: #277148;
12 | --ifm-color-primary-darkest: #205d3b;
13 | --ifm-color-primary-light: #33925d;
14 | --ifm-color-primary-lighter: #359962;
15 | --ifm-color-primary-lightest: #3cad6e;
16 | --ifm-code-font-size: 95%;
17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18 | }
19 |
20 | /* For readability concerns, you should choose a lighter palette in dark mode. */
21 | [data-theme='dark'] {
22 | --ifm-color-primary: #25c2a0;
23 | --ifm-color-primary-dark: #21af90;
24 | --ifm-color-primary-darker: #1fa588;
25 | --ifm-color-primary-darkest: #1a8870;
26 | --ifm-color-primary-light: #29d5b0;
27 | --ifm-color-primary-lighter: #32d8b4;
28 | --ifm-color-primary-lightest: #4fddbf;
29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30 | }
31 |
--------------------------------------------------------------------------------
/doc/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/.nojekyll
--------------------------------------------------------------------------------
/doc/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/favicon.ico
--------------------------------------------------------------------------------
/doc/static/img/flayer_chat_ui_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/flayer_chat_ui_screenshot.png
--------------------------------------------------------------------------------
/doc/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/doc/static/img/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/social-card.png
--------------------------------------------------------------------------------
/doc/static/img/supabase-disable-confirm-email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/supabase-disable-confirm-email.png
--------------------------------------------------------------------------------
/doc/static/img/supabase-project-credential.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/supabase-project-credential.png
--------------------------------------------------------------------------------
/doc/static/img/supabase-schema-exposure-setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/doc/static/img/supabase-schema-exposure-setting.png
--------------------------------------------------------------------------------
/doc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // This file is not used in compilation. It is here just for a nice editor experience.
3 | "extends": "@docusaurus/tsconfig",
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
46 | /lib/supabase_options_for_test.dart
47 | /lib/main_test.dart
48 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
17 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
18 | - platform: android
19 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
20 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
21 | - platform: ios
22 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
23 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
24 | - platform: linux
25 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
26 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
27 | - platform: macos
28 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
29 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
30 | - platform: web
31 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
32 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
33 | - platform: windows
34 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
35 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # example
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 |
14 | For help getting started with Flutter development, view the
15 | [online documentation](https://docs.flutter.dev/), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 | - always_declare_return_types
6 | - avoid_unused_constructor_parameters
7 | - directives_ordering
8 | - omit_local_variable_types
9 | - prefer_expression_function_bodies
10 | - prefer_final_fields
11 | - prefer_final_locals
12 | - prefer_relative_imports
13 | - prefer_single_quotes
14 | - sized_box_for_whitespace
15 | - sort_child_properties_last
16 | - sort_pub_dependencies
17 | - type_annotate_public_apis
18 | - unawaited_futures
19 | - use_named_constants
20 | - use_super_parameters
21 | - require_trailing_commas
22 |
23 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "kotlin-android"
4 | id "dev.flutter.flutter-gradle-plugin"
5 | }
6 |
7 | def localProperties = new Properties()
8 | def localPropertiesFile = rootProject.file('local.properties')
9 | if (localPropertiesFile.exists()) {
10 | localPropertiesFile.withReader('UTF-8') { reader ->
11 | localProperties.load(reader)
12 | }
13 | }
14 |
15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
16 | if (flutterVersionCode == null) {
17 | flutterVersionCode = '1'
18 | }
19 |
20 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
21 | if (flutterVersionName == null) {
22 | flutterVersionName = '1.0'
23 | }
24 |
25 | android {
26 | namespace "com.example"
27 | compileSdk flutter.compileSdkVersion
28 | ndkVersion flutter.ndkVersion
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 |
39 | sourceSets {
40 | main.java.srcDirs += 'src/main/kotlin'
41 | }
42 |
43 | defaultConfig {
44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
45 | applicationId "com.example"
46 | // You can update the following values to match your application needs.
47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
48 | minSdkVersion flutter.minSdkVersion
49 | targetSdkVersion flutter.targetSdkVersion
50 | versionCode flutterVersionCode.toInteger()
51 | versionName flutterVersionName
52 | }
53 |
54 | buildTypes {
55 | release {
56 | // TODO: Add your own signing config for the release build.
57 | // Signing with the debug keys for now, so `flutter run --release` works.
58 | signingConfig signingConfigs.debug
59 | }
60 | }
61 | }
62 |
63 | flutter {
64 | source '../..'
65 | }
66 |
67 | dependencies {}
68 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/example/untitled1/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity()
6 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 | subprojects {
13 | project.evaluationDependsOn(':app')
14 | }
15 |
16 | tasks.register("clean", Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4G
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
6 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version "7.3.0" apply false
23 | id "org.jetbrains.kotlin.android" version "1.9.0" apply false
24 | }
25 |
26 | include ":app"
27 |
--------------------------------------------------------------------------------
/example/assets/flyer_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/assets/flyer_logo.png
--------------------------------------------------------------------------------
/example/assets/flyer_logo.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/example/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | description: This file stores settings for Dart & Flutter DevTools.
2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3 | extensions:
4 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | example
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
3 | import 'package:supabase_flutter/supabase_flutter.dart';
4 |
5 | import 'src/pages/home.dart';
6 | import 'src/theme/color_schemes.dart';
7 | import 'supabase_options.dart';
8 |
9 | void main() async {
10 | WidgetsFlutterBinding.ensureInitialized();
11 | await Supabase.initialize(
12 | url: supabaseOptions.url,
13 | anonKey: supabaseOptions.anonKey,
14 | );
15 | runApp(const MyApp());
16 | }
17 |
18 | class MyApp extends StatelessWidget {
19 | const MyApp({
20 | super.key,
21 | });
22 |
23 | @override
24 | Widget build(BuildContext context) => MaterialApp(
25 | title: 'Supabase Chat',
26 | debugShowCheckedModeBanner: false,
27 | theme: ThemeData(
28 | useMaterial3: true,
29 | colorScheme: lightColorScheme,
30 | ),
31 | darkTheme: ThemeData(
32 | useMaterial3: true,
33 | colorScheme: darkColorScheme,
34 | ),
35 | themeMode: ThemeMode.dark,
36 | home: const UserOnlineStateObserver(
37 | child: HomePage(),
38 | ),
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/example/lib/src/class/message_status_ex.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
3 |
4 | extension MessageStatusEx on types.Status {
5 | IconData get icon {
6 | switch (this) {
7 | case types.Status.delivered:
8 | return Icons.done_all;
9 | case types.Status.error:
10 | return Icons.error_outline;
11 | case types.Status.seen:
12 | return Icons.done_all;
13 | case types.Status.sending:
14 | return Icons.timelapse;
15 | case types.Status.sent:
16 | return Icons.done;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/lib/src/class/user_ex.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
2 |
3 | extension UserEx on types.User {
4 | String getUserName() => firstName != null || lastName != null
5 | ? '${firstName ?? ''} ${lastName ?? ''}'.trim()
6 | : id;
7 | }
8 |
--------------------------------------------------------------------------------
/example/lib/src/pages/auth.dart:
--------------------------------------------------------------------------------
1 | import 'package:faker/faker.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
4 | import 'package:flutter_login/flutter_login.dart';
5 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
6 | import 'package:supabase_flutter/supabase_flutter.dart';
7 |
8 | import 'home.dart';
9 |
10 | class AuthScreen extends StatefulWidget {
11 | const AuthScreen({
12 | super.key,
13 | });
14 |
15 | @override
16 | State createState() => _AuthScreenState();
17 | }
18 |
19 | class _AuthScreenState extends State {
20 | final faker = Faker();
21 |
22 | @override
23 | Widget build(BuildContext context) => FlutterLogin(
24 | logo: const AssetImage('assets/flyer_logo.png'),
25 | savedEmail: faker.internet.email(),
26 | savedPassword: 'Qawsed1-', //faker.internet.password(),
27 | navigateBackAfterRecovery: true,
28 | additionalSignupFields: [
29 | UserFormField(
30 | keyName: 'first_name',
31 | displayName: 'First name',
32 | defaultValue: faker.person.firstName(),
33 | fieldValidator: (value) {
34 | if (value == null || value == '') return 'Required';
35 | return null;
36 | },
37 | ),
38 | UserFormField(
39 | keyName: 'last_name',
40 | displayName: 'Last name',
41 | defaultValue: faker.person.lastName(),
42 | fieldValidator: (value) {
43 | if (value == null || value == '') return 'Required';
44 | return null;
45 | },
46 | ),
47 | ],
48 | passwordValidator: (value) {
49 | if (value!.isEmpty) {
50 | return 'Password is empty';
51 | }
52 | return null;
53 | },
54 | onLogin: (loginData) async {
55 | try {
56 | await Supabase.instance.client.auth.signInWithPassword(
57 | email: loginData.name,
58 | password: loginData.password,
59 | );
60 | } catch (e) {
61 | return e.toString();
62 | }
63 | return null;
64 | },
65 | onSignup: (signupData) async {
66 | try {
67 | final response = await Supabase.instance.client.auth.signUp(
68 | email: signupData.name,
69 | password: signupData.password!,
70 | );
71 | await SupabaseChatCore.instance.updateUser(
72 | types.User(
73 | firstName: signupData.additionalSignupData!['first_name'],
74 | id: response.user!.id,
75 | lastName: signupData.additionalSignupData!['last_name'],
76 | ),
77 | );
78 | } catch (e) {
79 | return e.toString();
80 | }
81 | return null;
82 | },
83 | onSubmitAnimationCompleted: () {
84 | Navigator.of(context).pushReplacement(
85 | MaterialPageRoute(
86 | builder: (context) => const HomePage(),
87 | ),
88 | );
89 | },
90 | onRecoverPassword: (name) async {
91 | try {
92 | await Supabase.instance.client.auth.resetPasswordForEmail(
93 | name,
94 | );
95 | } catch (e) {
96 | return e.toString();
97 | }
98 | return null;
99 | },
100 | initialAuthMode: AuthMode.signup,
101 | );
102 | }
103 |
--------------------------------------------------------------------------------
/example/lib/src/pages/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:supabase_flutter/supabase_flutter.dart';
4 |
5 | import 'auth.dart';
6 | import 'rooms.dart';
7 | import 'users.dart';
8 |
9 | class HomePage extends StatefulWidget {
10 | const HomePage({super.key});
11 |
12 | @override
13 | State createState() => _HomePageState();
14 | }
15 |
16 | class _HomePageState extends State {
17 | bool _error = false;
18 | bool _initialized = false;
19 | User? _user;
20 |
21 | @override
22 | void initState() {
23 | initializeSupabase();
24 | super.initState();
25 | }
26 |
27 | void initializeSupabase() async {
28 | try {
29 | Supabase.instance.client.auth.onAuthStateChange.listen((data) {
30 | setState(() {
31 | _user = data.session?.user;
32 | });
33 | });
34 | setState(() {
35 | _initialized = true;
36 | });
37 | } catch (e) {
38 | setState(() {
39 | _error = true;
40 | });
41 | }
42 | }
43 |
44 | void logout() async {
45 | await Supabase.instance.client.auth.signOut();
46 | }
47 |
48 | @override
49 | Widget build(BuildContext context) {
50 | if (_error) {
51 | return Container();
52 | }
53 |
54 | if (!_initialized) {
55 | return Container();
56 | }
57 |
58 | return Scaffold(
59 | appBar: AppBar(
60 | actions: [
61 | IconButton(
62 | icon: const Icon(
63 | Icons.add,
64 | ),
65 | onPressed: _user == null
66 | ? null
67 | : () {
68 | Navigator.of(context).push(
69 | MaterialPageRoute(
70 | fullscreenDialog: true,
71 | builder: (context) => const UsersPage(),
72 | ),
73 | );
74 | },
75 | ),
76 | ],
77 | leading: IconButton(
78 | icon: const Icon(Icons.logout),
79 | onPressed: _user == null ? null : logout,
80 | ),
81 | systemOverlayStyle: SystemUiOverlayStyle.light,
82 | title: const Text('Rooms'),
83 | ),
84 | body: _user == null
85 | ? Container(
86 | alignment: Alignment.center,
87 | margin: const EdgeInsets.only(
88 | bottom: 200,
89 | ),
90 | child: Column(
91 | mainAxisAlignment: MainAxisAlignment.center,
92 | children: [
93 | const Text('Not authenticated'),
94 | TextButton(
95 | onPressed: () {
96 | Navigator.of(context).push(
97 | MaterialPageRoute(
98 | fullscreenDialog: true,
99 | builder: (context) => const AuthScreen(),
100 | ),
101 | );
102 | },
103 | child: const Text('Login'),
104 | ),
105 | ],
106 | ),
107 | )
108 | : RoomsPage(),
109 | );
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/example/lib/src/pages/rooms.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
3 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
4 | import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
5 |
6 | import '../widgets/room_tile.dart';
7 | import 'room.dart';
8 |
9 | class RoomsPage extends StatefulWidget {
10 | const RoomsPage({super.key});
11 |
12 | @override
13 | State createState() => _RoomsPageState();
14 | }
15 |
16 | class _RoomsPageState extends State {
17 | static const _pageSize = 20;
18 | String _filter = '';
19 |
20 | final PagingController _controller =
21 | PagingController(firstPageKey: 0);
22 |
23 | @override
24 | void initState() {
25 | _controller.addPageRequestListener((pageKey) {
26 | _fetchPage(pageKey);
27 | });
28 | super.initState();
29 | }
30 |
31 | @override
32 | void dispose() {
33 | _controller.dispose();
34 | super.dispose();
35 | }
36 |
37 | void _setFilters(String filter) {
38 | WidgetsBinding.instance.addPostFrameCallback((_) {
39 | _filter = filter;
40 | if (mounted) {
41 | _controller.nextPageKey = 0;
42 | _controller.refresh();
43 | }
44 | });
45 | }
46 |
47 | Future _fetchPage(int offset) async {
48 | try {
49 | final newItems = await SupabaseChatCore.instance
50 | .rooms(filter: _filter, offset: offset, limit: _pageSize);
51 | final isLastPage = newItems.length < _pageSize;
52 | if (isLastPage) {
53 | _controller.appendLastPage(newItems);
54 | } else {
55 | final nextPageKey = offset + newItems.length;
56 | _controller.appendPage(newItems, nextPageKey);
57 | }
58 | } catch (error) {
59 | _controller.error = error;
60 | }
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) => Column(
65 | crossAxisAlignment: CrossAxisAlignment.center,
66 | children: [
67 | FractionallySizedBox(
68 | widthFactor: .5,
69 | child: TextField(
70 | decoration: InputDecoration(
71 | border: OutlineInputBorder(),
72 | labelText: 'Search',
73 | ),
74 | onChanged: (value) => _setFilters(value),
75 | ),
76 | ),
77 | Expanded(
78 | child: RefreshIndicator(
79 | onRefresh: () async {
80 | WidgetsBinding.instance.addPostFrameCallback((_) {
81 | if (mounted) {
82 | _controller.nextPageKey = 0;
83 | _controller.refresh();
84 | }
85 | });
86 | },
87 | child: StreamBuilder>(
88 | stream: SupabaseChatCore.instance.roomsUpdates(),
89 | builder: (context, snapshot) {
90 | WidgetsBinding.instance.addPostFrameCallback((_) {
91 | if (mounted) {
92 | if (_filter == '' && snapshot.data != null) {
93 | _controller.itemList = SupabaseChatCore.updateRoomList(
94 | _controller.itemList ?? [],
95 | snapshot.data!,
96 | );
97 | }
98 | }
99 | });
100 | return PagedListView(
101 | pagingController: _controller,
102 | builderDelegate: PagedChildBuilderDelegate(
103 | itemBuilder: (context, room, index) => RoomTile(
104 | room: room,
105 | onTap: (room) {
106 | Navigator.of(context).push(
107 | MaterialPageRoute(
108 | builder: (context) => RoomPage(
109 | room: room,
110 | ),
111 | ),
112 | );
113 | },
114 | ),
115 | ),
116 | );
117 | },
118 | ),
119 | ),
120 | ),
121 | ],
122 | );
123 | }
124 |
--------------------------------------------------------------------------------
/example/lib/src/pages/users.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
4 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
5 | import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
6 |
7 | import '../widgets/user_tile.dart';
8 | import 'room.dart';
9 |
10 | class UsersPage extends StatefulWidget {
11 | const UsersPage({super.key});
12 |
13 | @override
14 | State createState() => _UsersPageState();
15 | }
16 |
17 | class _UsersPageState extends State {
18 | static const _pageSize = 20;
19 | String _filter = '';
20 |
21 | final PagingController _controller =
22 | PagingController(firstPageKey: 0);
23 |
24 | @override
25 | void initState() {
26 | _controller.addPageRequestListener((pageKey) {
27 | _fetchPage(pageKey);
28 | });
29 | super.initState();
30 | }
31 |
32 | @override
33 | void dispose() {
34 | _controller.dispose();
35 | super.dispose();
36 | }
37 |
38 | void _setFilters(String filter) {
39 | WidgetsBinding.instance.addPostFrameCallback((_) {
40 | _filter = filter;
41 | if (mounted) {
42 | _controller.nextPageKey = 0;
43 | _controller.refresh();
44 | }
45 | });
46 | }
47 |
48 | Future _fetchPage(int offset) async {
49 | try {
50 | final newItems = await SupabaseChatCore.instance
51 | .users(filter: _filter, offset: offset, limit: _pageSize);
52 | final isLastPage = newItems.length < _pageSize;
53 | if (isLastPage) {
54 | _controller.appendLastPage(newItems);
55 | } else {
56 | final nextPageKey = offset + newItems.length;
57 | _controller.appendPage(newItems, nextPageKey);
58 | }
59 | } catch (error) {
60 | _controller.error = error;
61 | }
62 | }
63 |
64 | void _handlePressed(types.User otherUser, BuildContext context) async {
65 | final navigator = Navigator.of(context);
66 | final room = await SupabaseChatCore.instance.createRoom(otherUser);
67 |
68 | navigator.pop();
69 | await navigator.push(
70 | MaterialPageRoute(
71 | builder: (context) => RoomPage(
72 | room: room,
73 | ),
74 | ),
75 | );
76 | }
77 |
78 | @override
79 | Widget build(BuildContext context) => Scaffold(
80 | appBar: AppBar(
81 | systemOverlayStyle: SystemUiOverlayStyle.light,
82 | title: const Text('Users'),
83 | ),
84 | body: Column(
85 | crossAxisAlignment: CrossAxisAlignment.center,
86 | children: [
87 | FractionallySizedBox(
88 | widthFactor: .5,
89 | child: TextField(
90 | decoration: InputDecoration(
91 | border: OutlineInputBorder(),
92 | labelText: 'Search',
93 | ),
94 | onChanged: (value) => _setFilters(value),
95 | ),
96 | ),
97 | Expanded(
98 | child: PagedListView(
99 | pagingController: _controller,
100 | builderDelegate: PagedChildBuilderDelegate(
101 | itemBuilder: (context, user, index) => UserTile(
102 | user: user,
103 | onTap: (user) {
104 | _handlePressed(user, context);
105 | },
106 | ),
107 | ),
108 | ),
109 | ),
110 | ],
111 | ),
112 | );
113 | }
114 |
--------------------------------------------------------------------------------
/example/lib/src/theme/color_schemes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const lightColorScheme = ColorScheme(
4 | brightness: Brightness.light,
5 | primary: Color(0xFF6750A4),
6 | onPrimary: Color(0xFFFFFFFF),
7 | primaryContainer: Color(0xFFEADDFF),
8 | onPrimaryContainer: Color(0xFF21005D),
9 | secondary: Color(0xFF625B71),
10 | onSecondary: Color(0xFFFFFFFF),
11 | secondaryContainer: Color(0xFFE8DEF8),
12 | onSecondaryContainer: Color(0xFF1D192B),
13 | tertiary: Color(0xFF7D5260),
14 | onTertiary: Color(0xFFFFFFFF),
15 | tertiaryContainer: Color(0xFFFFD8E4),
16 | onTertiaryContainer: Color(0xFF31111D),
17 | error: Color(0xFFB3261E),
18 | onError: Color(0xFFFFFFFF),
19 | errorContainer: Color(0xFFF9DEDC),
20 | onErrorContainer: Color(0xFF410E0B),
21 | outline: Color(0xFF79747E),
22 | surface: Color(0xFFFFFBFE),
23 | onSurface: Color(0xFF1C1B1F),
24 | surfaceContainerHighest: Color(0xFFE7E0EC),
25 | onSurfaceVariant: Color(0xFF49454F),
26 | inverseSurface: Color(0xFF313033),
27 | onInverseSurface: Color(0xFFF4EFF4),
28 | inversePrimary: Color(0xFFD0BCFF),
29 | shadow: Color(0xFF000000),
30 | surfaceTint: Color(0xFF6750A4),
31 | outlineVariant: Color(0xFFCAC4D0),
32 | scrim: Color(0xFF000000),
33 | );
34 |
35 | const darkColorScheme = ColorScheme(
36 | brightness: Brightness.dark,
37 | primary: Color(0xFFD0BCFF),
38 | onPrimary: Color(0xFF381E72),
39 | primaryContainer: Color(0xFF4F378B),
40 | onPrimaryContainer: Color(0xFFEADDFF),
41 | secondary: Color(0xFFCCC2DC),
42 | onSecondary: Color(0xFF332D41),
43 | secondaryContainer: Color(0xFF4A4458),
44 | onSecondaryContainer: Color(0xFFE8DEF8),
45 | tertiary: Color(0xFFEFB8C8),
46 | onTertiary: Color(0xFF492532),
47 | tertiaryContainer: Color(0xFF633B48),
48 | onTertiaryContainer: Color(0xFFFFD8E4),
49 | error: Color(0xFFF2B8B5),
50 | onError: Color(0xFF601410),
51 | errorContainer: Color(0xFF8C1D18),
52 | onErrorContainer: Color(0xFFF9DEDC),
53 | outline: Color(0xFF938F99),
54 | surface: Color(0xFF1C1B1F),
55 | onSurface: Color(0xFFE6E1E5),
56 | surfaceContainerHighest: Color(0xFF49454F),
57 | onSurfaceVariant: Color(0xFFCAC4D0),
58 | inverseSurface: Color(0xFFE6E1E5),
59 | onInverseSurface: Color(0xFF313033),
60 | inversePrimary: Color(0xFF6750A4),
61 | shadow: Color(0xFF000000),
62 | surfaceTint: Color(0xFFD0BCFF),
63 | outlineVariant: Color(0xFF49454F),
64 | scrim: Color(0xFF000000),
65 | );
66 |
--------------------------------------------------------------------------------
/example/lib/src/util.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | const colors = [
4 | Color(0xffff6767),
5 | Color(0xff66e0da),
6 | Color(0xfff5a2d9),
7 | Color(0xfff0c722),
8 | Color(0xff6a85e5),
9 | Color(0xfffd9a6f),
10 | Color(0xff92db6e),
11 | Color(0xff73b8e5),
12 | Color(0xfffd7590),
13 | Color(0xffc78ae5),
14 | ];
15 |
16 | Color getAvatarColor(String name) {
17 | final index = name.hashCode % colors.length;
18 | return colors[index];
19 | }
20 |
--------------------------------------------------------------------------------
/example/lib/src/widgets/room_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
3 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
4 | import 'package:timeago/timeago.dart' as timeago;
5 |
6 | import '../class/message_status_ex.dart';
7 | import '../util.dart';
8 |
9 | class RoomTile extends StatelessWidget {
10 | final types.Room room;
11 | final ValueChanged onTap;
12 |
13 | const RoomTile({
14 | super.key,
15 | required this.room,
16 | required this.onTap,
17 | });
18 |
19 | Widget _buildAvatar(types.Room room) {
20 | final color = getAvatarColor(room.id);
21 | var otherUserIndex = -1;
22 | types.User? otherUser;
23 |
24 | if (room.type == types.RoomType.direct) {
25 | otherUserIndex = room.users.indexWhere(
26 | (u) => u.id != SupabaseChatCore.instance.loggedSupabaseUser!.id,
27 | );
28 | if (otherUserIndex >= 0) {
29 | otherUser = room.users[otherUserIndex];
30 | }
31 | }
32 |
33 | final hasImage = room.imageUrl != null;
34 | final name = room.name ?? '';
35 | final Widget child = CircleAvatar(
36 | backgroundColor: hasImage ? Colors.transparent : color,
37 | backgroundImage: hasImage ? NetworkImage(room.imageUrl!) : null,
38 | radius: 20,
39 | child: !hasImage
40 | ? Text(
41 | name.isEmpty ? '' : name[0].toUpperCase(),
42 | style: const TextStyle(color: Colors.white),
43 | )
44 | : null,
45 | );
46 | if (otherUser == null) {
47 | return Padding(
48 | padding: const EdgeInsets.only(right: 16),
49 | child: child,
50 | );
51 | }
52 | return Padding(
53 | padding: const EdgeInsets.only(right: 16),
54 | child: UserOnlineStatusWidget(
55 | uid: otherUser.id,
56 | builder: (status) => Stack(
57 | alignment: Alignment.bottomRight,
58 | children: [
59 | child,
60 | if (status == UserOnlineStatus.online)
61 | Container(
62 | width: 10,
63 | height: 10,
64 | margin: const EdgeInsets.only(
65 | right: 3,
66 | bottom: 3,
67 | ),
68 | decoration: BoxDecoration(
69 | color: Colors.green,
70 | shape: BoxShape.circle,
71 | border: Border.all(
72 | color: Colors.white,
73 | width: 2,
74 | ),
75 | ),
76 | ),
77 | ],
78 | ),
79 | ),
80 | );
81 | }
82 |
83 | @override
84 | Widget build(BuildContext context) => ListTile(
85 | key: ValueKey(room.id),
86 | leading: _buildAvatar(room),
87 | title: Row(
88 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
89 | children: [
90 | Text(room.name ?? ''),
91 | if (room.lastMessages?.isNotEmpty == true)
92 | Row(
93 | crossAxisAlignment: CrossAxisAlignment.end,
94 | children: [
95 | Text(
96 | timeago.format(
97 | DateTime.now().subtract(
98 | Duration(
99 | milliseconds: DateTime.now().millisecondsSinceEpoch -
100 | (room.updatedAt ?? 0),
101 | ),
102 | ),
103 | locale: 'en_short',
104 | ),
105 | ),
106 | if (room.lastMessages!.first.status != null)
107 | Padding(
108 | padding: const EdgeInsets.only(left: 8.0),
109 | child: Icon(
110 | size: 20,
111 | room.lastMessages!.first.status!.icon,
112 | color:
113 | room.lastMessages!.first.status == types.Status.seen
114 | ? Colors.lightBlue
115 | : null,
116 | ),
117 | ),
118 | ],
119 | ),
120 | ],
121 | ),
122 | subtitle: room.lastMessages?.isNotEmpty == true &&
123 | room.lastMessages!.first is types.TextMessage
124 | ? Text(
125 | (room.lastMessages!.first as types.TextMessage).text,
126 | maxLines: 1,
127 | overflow: TextOverflow.ellipsis,
128 | )
129 | : null,
130 | onTap: () => onTap(room),
131 | );
132 | }
133 |
--------------------------------------------------------------------------------
/example/lib/src/widgets/user_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
3 | import 'package:flutter_supabase_chat_core/flutter_supabase_chat_core.dart';
4 |
5 | import '../class/user_ex.dart';
6 | import '../util.dart';
7 |
8 | class UserTile extends StatelessWidget {
9 | final types.User user;
10 | final ValueChanged onTap;
11 |
12 | const UserTile({
13 | super.key,
14 | required this.user,
15 | required this.onTap,
16 | });
17 |
18 | Widget _buildAvatar(types.User user) {
19 | final color = getAvatarColor(user.id);
20 | final hasImage = user.imageUrl != null;
21 | final name = user.getUserName();
22 | return Container(
23 | margin: const EdgeInsets.only(right: 16),
24 | child: UserOnlineStatusWidget(
25 | uid: user.id,
26 | builder: (status) => Stack(
27 | alignment: Alignment.bottomRight,
28 | children: [
29 | CircleAvatar(
30 | backgroundColor: hasImage ? Colors.transparent : color,
31 | backgroundImage: hasImage ? NetworkImage(user.imageUrl!) : null,
32 | radius: 20,
33 | child: !hasImage
34 | ? Text(
35 | name.isEmpty ? '' : name[0].toUpperCase(),
36 | style: const TextStyle(color: Colors.white),
37 | )
38 | : null,
39 | ),
40 | if (status == UserOnlineStatus.online)
41 | Container(
42 | width: 10,
43 | height: 10,
44 | margin: const EdgeInsets.only(right: 3, bottom: 3),
45 | decoration: BoxDecoration(
46 | color: Colors.green,
47 | shape: BoxShape.circle,
48 | border: Border.all(
49 | color: Colors.white,
50 | width: 2,
51 | ),
52 | ),
53 | ),
54 | ],
55 | ),
56 | ),
57 | );
58 | }
59 |
60 | @override
61 | Widget build(BuildContext context) => ListTile(
62 | leading: _buildAvatar(user),
63 | title: Text(user.getUserName()),
64 | onTap: () => onTap(user),
65 | );
66 | }
67 |
--------------------------------------------------------------------------------
/example/lib/supabase_options.dart:
--------------------------------------------------------------------------------
1 | class SupabaseOptions {
2 | final String url;
3 | final String anonKey;
4 |
5 | SupabaseOptions({
6 | required this.url,
7 | required this.anonKey,
8 | });
9 | }
10 |
11 | final SupabaseOptions supabaseOptions = SupabaseOptions(
12 | url: 'https://{{your_project_reference_id}}.supabase.co',
13 | anonKey: '{{supabase_anon_key}}',
14 | );
15 |
--------------------------------------------------------------------------------
/example/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/example/linux/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.10)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 |
12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13 | # which isn't available in 3.10.
14 | function(list_prepend LIST_NAME PREFIX)
15 | set(NEW_LIST "")
16 | foreach(element ${${LIST_NAME}})
17 | list(APPEND NEW_LIST "${PREFIX}${element}")
18 | endforeach(element)
19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20 | endfunction()
21 |
22 | # === Flutter Library ===
23 | # System-level dependencies.
24 | find_package(PkgConfig REQUIRED)
25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28 |
29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30 |
31 | # Published to parent scope for install step.
32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36 |
37 | list(APPEND FLUTTER_LIBRARY_HEADERS
38 | "fl_basic_message_channel.h"
39 | "fl_binary_codec.h"
40 | "fl_binary_messenger.h"
41 | "fl_dart_project.h"
42 | "fl_engine.h"
43 | "fl_json_message_codec.h"
44 | "fl_json_method_codec.h"
45 | "fl_message_codec.h"
46 | "fl_method_call.h"
47 | "fl_method_channel.h"
48 | "fl_method_codec.h"
49 | "fl_method_response.h"
50 | "fl_plugin_registrar.h"
51 | "fl_plugin_registry.h"
52 | "fl_standard_message_codec.h"
53 | "fl_standard_method_codec.h"
54 | "fl_string_codec.h"
55 | "fl_value.h"
56 | "fl_view.h"
57 | "flutter_linux.h"
58 | )
59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60 | add_library(flutter INTERFACE)
61 | target_include_directories(flutter INTERFACE
62 | "${EPHEMERAL_DIR}"
63 | )
64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65 | target_link_libraries(flutter INTERFACE
66 | PkgConfig::GTK
67 | PkgConfig::GLIB
68 | PkgConfig::GIO
69 | )
70 | add_dependencies(flutter flutter_assemble)
71 |
72 | # === Flutter tool backend ===
73 | # _phony_ is a non-existent file to force this command to run every time,
74 | # since currently there's no way to get a full input/output list from the
75 | # flutter tool.
76 | add_custom_command(
77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79 | COMMAND ${CMAKE_COMMAND} -E env
80 | ${FLUTTER_TOOL_ENVIRONMENT}
81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83 | VERBATIM
84 | )
85 | add_custom_target(flutter_assemble DEPENDS
86 | "${FLUTTER_LIBRARY}"
87 | ${FLUTTER_LIBRARY_HEADERS}
88 | )
89 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void fl_register_plugins(FlPluginRegistry* registry) {
15 | g_autoptr(FlPluginRegistrar) file_saver_registrar =
16 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
17 | file_saver_plugin_register_with_registrar(file_saver_registrar);
18 | g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
19 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
20 | file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
21 | g_autoptr(FlPluginRegistrar) gtk_registrar =
22 | fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
23 | gtk_plugin_register_with_registrar(gtk_registrar);
24 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
25 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
26 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
27 | }
28 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | file_saver
7 | file_selector_linux
8 | gtk
9 | url_launcher_linux
10 | )
11 |
12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 | )
14 |
15 | set(PLUGIN_BUNDLED_LIBRARIES)
16 |
17 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
22 | endforeach(plugin)
23 |
24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
27 | endforeach(ffi_plugin)
28 |
--------------------------------------------------------------------------------
/example/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/example/linux/my_application.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | #include
4 | #ifdef GDK_WINDOWING_X11
5 | #include
6 | #endif
7 |
8 | #include "flutter/generated_plugin_registrant.h"
9 |
10 | struct _MyApplication {
11 | GtkApplication parent_instance;
12 | char** dart_entrypoint_arguments;
13 | };
14 |
15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 |
17 | // Implements GApplication::activate.
18 | static void my_application_activate(GApplication* application) {
19 | MyApplication* self = MY_APPLICATION(application);
20 | GtkWindow* window =
21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 |
23 | // Use a header bar when running in GNOME as this is the common style used
24 | // by applications and is the setup most users will be using (e.g. Ubuntu
25 | // desktop).
26 | // If running on X and not using GNOME then just use a traditional title bar
27 | // in case the window manager does more exotic layout, e.g. tiling.
28 | // If running on Wayland assume the header bar will work (may need changing
29 | // if future cases occur).
30 | gboolean use_header_bar = TRUE;
31 | #ifdef GDK_WINDOWING_X11
32 | GdkScreen* screen = gtk_window_get_screen(window);
33 | if (GDK_IS_X11_SCREEN(screen)) {
34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 | use_header_bar = FALSE;
37 | }
38 | }
39 | #endif
40 | if (use_header_bar) {
41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 | gtk_widget_show(GTK_WIDGET(header_bar));
43 | gtk_header_bar_set_title(header_bar, "example");
44 | gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 | } else {
47 | gtk_window_set_title(window, "example");
48 | }
49 |
50 | gtk_window_set_default_size(window, 1280, 720);
51 | gtk_widget_show(GTK_WIDGET(window));
52 |
53 | g_autoptr(FlDartProject) project = fl_dart_project_new();
54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
55 |
56 | FlView* view = fl_view_new(project);
57 | gtk_widget_show(GTK_WIDGET(view));
58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
59 |
60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view));
61 |
62 | gtk_widget_grab_focus(GTK_WIDGET(view));
63 | }
64 |
65 | // Implements GApplication::local_command_line.
66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
67 | MyApplication* self = MY_APPLICATION(application);
68 | // Strip out the first argument as it is the binary name.
69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
70 |
71 | g_autoptr(GError) error = nullptr;
72 | if (!g_application_register(application, nullptr, &error)) {
73 | g_warning("Failed to register: %s", error->message);
74 | *exit_status = 1;
75 | return TRUE;
76 | }
77 |
78 | g_application_activate(application);
79 | *exit_status = 0;
80 |
81 | return TRUE;
82 | }
83 |
84 | // Implements GObject::dispose.
85 | static void my_application_dispose(GObject* object) {
86 | MyApplication* self = MY_APPLICATION(object);
87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
89 | }
90 |
91 | static void my_application_class_init(MyApplicationClass* klass) {
92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate;
93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
95 | }
96 |
97 | static void my_application_init(MyApplication* self) {}
98 |
99 | MyApplication* my_application_new() {
100 | return MY_APPLICATION(g_object_new(my_application_get_type(),
101 | "application-id", APPLICATION_ID,
102 | "flags", G_APPLICATION_NON_UNIQUE,
103 | nullptr));
104 | }
105 |
--------------------------------------------------------------------------------
/example/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/example/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/example/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.14'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | target 'RunnerTests' do
35 | inherit! :search_paths
36 | end
37 | end
38 |
39 | post_install do |installer|
40 | installer.pods_project.targets.each do |target|
41 | flutter_additional_macos_build_settings(target)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @NSApplicationMain
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "app_icon_16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "app_icon_32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "app_icon_32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "app_icon_64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "app_icon_128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "app_icon_256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "app_icon_256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "app_icon_512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "app_icon_512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "app_icon_1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = example
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.example
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.. All rights reserved.
15 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/example/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.client
10 |
11 | com.apple.security.network.server
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/example/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/example/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import FlutterMacOS
2 | import Cocoa
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: example
2 | description: A new Flutter project.
3 | publish_to: 'none'
4 |
5 | version: 1.5.0
6 |
7 | environment:
8 | sdk: '>=3.4.0 <4.0.0'
9 |
10 | dependencies:
11 | cupertino_icons: ^1.0.8
12 | dio: ^5.8.0+1
13 | faker: ^2.2.0
14 | file_picker: ^8.3.1
15 | file_saver: ^0.2.14
16 | flutter:
17 | sdk: flutter
18 | flutter_chat_types: ^3.6.2
19 | flutter_chat_ui: ^1.6.15
20 | flutter_login: ^5.0.0
21 | flutter_supabase_chat_core:
22 | path: ../
23 | flutter_svg: ^2.0.17
24 | http: ^1.3.0
25 | image_picker: ^1.1.2
26 | infinite_scroll_pagination: ^4.1.0
27 | open_filex: ^4.6.0
28 | path_provider: ^2.1.5
29 | supabase_flutter: ^2.8.3
30 | timeago: ^3.7.0
31 |
32 |
33 | dev_dependencies:
34 | flutter_lints: ^5.0.0
35 |
36 | flutter:
37 | uses-material-design: true
38 | assets:
39 | - assets/
--------------------------------------------------------------------------------
/example/utils/prepare.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | [string]$hostname,
3 | [int]$port,
4 | [string]$database,
5 | [string]$user
6 | )
7 |
8 | try {
9 | Get-Command psql.exe -ErrorAction Stop
10 | }
11 | catch {
12 | Write-Error "psql was not found. Please ensure PostgreSQL is installed and that psql is in your PATH."
13 | exit
14 | }
15 |
16 | $psqlCommand = "psql -U $user -h $hostname -p $port -d $database"
17 |
18 | Invoke-Expression "$psqlCommand -f .\sql\01_database_schema.sql"
19 | Invoke-Expression "$psqlCommand -f .\sql\02_database_trigger.sql"
20 | Invoke-Expression "$psqlCommand -f .\sql\03_database_policy.sql"
21 | Invoke-Expression "$psqlCommand -f .\sql\04_storage.sql"
22 | Invoke-Expression "$psqlCommand -f .\sql\05_database_view.sql"
23 | Invoke-Expression "$psqlCommand -f .\sql\99_database_schema_permission.sql"
24 |
--------------------------------------------------------------------------------
/example/utils/prepare.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | while getopts h:p:d:U: flag
4 | do
5 | case "${flag}" in
6 | h) hostname=${OPTARG};;
7 | p) port=${OPTARG};;
8 | d) database=${OPTARG};;
9 | U) user=${OPTARG};;
10 | esac
11 | done
12 |
13 | psql -U $user -h $hostname -p $port -d $database -f ./sql/01_database_schema.sql
14 | psql -U $user -h $hostname -p $port -d $database -f ./sql/02_database_trigger.sql
15 | psql -U $user -h $hostname -p $port -d $database -f ./sql/03_database_policy.sql
16 | psql -U $user -h $hostname -p $port -d $database -f ./sql/04_storage.sql
17 | psql -U $user -h $hostname -p $port -d $database -f ./sql/05_database_view.sql
18 | psql -U $user -h $hostname -p $port -d $database -f ./sql/99_database_schema_permission.sql
--------------------------------------------------------------------------------
/example/utils/sql/01_database_schema.sql:
--------------------------------------------------------------------------------
1 | SET statement_timeout = 0;
2 | SET lock_timeout = 0;
3 | SET idle_in_transaction_session_timeout = 0;
4 | SET client_encoding = 'UTF8';
5 | SET standard_conforming_strings = on;
6 | SELECT pg_catalog.set_config('search_path', '', false);
7 | SET check_function_bodies = false;
8 | SET xmloption = content;
9 | SET client_min_messages = warning;
10 | SET row_security = off;
11 |
12 | CREATE SCHEMA chats;
13 |
14 | ALTER SCHEMA chats OWNER TO postgres;
15 |
16 | SET default_tablespace = '';
17 |
18 | SET default_table_access_method = heap;
19 |
20 | CREATE TABLE chats.messages (
21 | id bigint NOT NULL,
22 | "createdAt" bigint,
23 | metadata jsonb,
24 | duration bigint,
25 | "mimeType" text,
26 | name text,
27 | "remoteId" text,
28 | "repliedMessage" jsonb,
29 | "roomId" bigint NOT NULL,
30 | "showStatus" boolean,
31 | size bigint,
32 | status text,
33 | type text,
34 | "updatedAt" bigint,
35 | uri text,
36 | "waveForm" jsonb,
37 | "isLoading" boolean,
38 | height double precision,
39 | width double precision,
40 | "previewData" jsonb,
41 | "authorId" uuid NOT NULL,
42 | text text
43 | );
44 |
45 | ALTER TABLE chats.messages OWNER TO postgres;
46 |
47 | ALTER TABLE chats.messages ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
48 | SEQUENCE NAME chats.messages_id_seq
49 | START WITH 1
50 | INCREMENT BY 1
51 | NO MINVALUE
52 | NO MAXVALUE
53 | CACHE 1
54 | );
55 |
56 | CREATE TABLE chats.rooms (
57 | id bigint NOT NULL,
58 | "imageUrl" text,
59 | metadata jsonb,
60 | name text,
61 | type text,
62 | "userIds" uuid[] NOT NULL,
63 | "lastMessages" jsonb,
64 | "userRoles" jsonb,
65 | "createdAt" bigint NOT NULL,
66 | "updatedAt" bigint NOT NULL
67 | );
68 |
69 | ALTER TABLE chats.rooms OWNER TO postgres;
70 |
71 | ALTER TABLE chats.rooms ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
72 | SEQUENCE NAME chats.rooms_id_seq
73 | START WITH 1
74 | INCREMENT BY 1
75 | NO MINVALUE
76 | NO MAXVALUE
77 | CACHE 1
78 | );
79 |
80 | CREATE TABLE chats.users (
81 | "firstName" text,
82 | "imageUrl" text,
83 | "lastName" text,
84 | metadata jsonb,
85 | role text,
86 | id uuid NOT NULL,
87 | "createdAt" bigint NOT NULL,
88 | "updatedAt" bigint NOT NULL,
89 | "lastSeen" bigint NOT NULL
90 | );
91 |
92 | ALTER TABLE chats.users OWNER TO postgres;
93 |
94 | ALTER TABLE ONLY chats.messages
95 | ADD CONSTRAINT messages_pkey PRIMARY KEY (id);
96 |
97 | ALTER TABLE ONLY chats.rooms
98 | ADD CONSTRAINT rooms_pkey PRIMARY KEY (id);
99 |
100 | ALTER TABLE ONLY chats.users
101 | ADD CONSTRAINT users_pkey PRIMARY KEY (id);
102 |
103 | ALTER TABLE ONLY chats.messages
104 | ADD CONSTRAINT "messages_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES auth.users(id) ON DELETE CASCADE;
105 |
106 | ALTER TABLE ONLY chats.messages
107 | ADD CONSTRAINT "messages_roomId_fkey" FOREIGN KEY ("roomId") REFERENCES chats.rooms(id) ON UPDATE CASCADE ON DELETE CASCADE;
108 |
109 | ALTER TABLE ONLY chats.users
110 | ADD CONSTRAINT users_id_fkey FOREIGN KEY (id) REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE;
111 |
112 | CREATE INDEX ON "chats"."messages" USING btree ("authorId");
113 | CREATE INDEX ON "chats"."messages" USING btree ("roomId");
114 |
115 | ALTER TABLE chats.messages ENABLE ROW LEVEL SECURITY;
116 |
117 | ALTER TABLE chats.rooms ENABLE ROW LEVEL SECURITY;
118 |
119 | ALTER TABLE chats.users ENABLE ROW LEVEL SECURITY;
120 |
121 | REVOKE USAGE ON SCHEMA chats FROM PUBLIC;
122 | GRANT USAGE ON SCHEMA chats TO anon;
123 | GRANT USAGE ON SCHEMA chats TO authenticated;
124 | GRANT USAGE ON SCHEMA chats TO service_role;
125 |
126 | GRANT ALL ON TABLE chats.messages TO anon;
127 | GRANT ALL ON TABLE chats.messages TO authenticated;
128 | GRANT ALL ON TABLE chats.messages TO service_role;
129 |
130 | GRANT ALL ON SEQUENCE chats.messages_id_seq TO anon;
131 | GRANT ALL ON SEQUENCE chats.messages_id_seq TO authenticated;
132 | GRANT ALL ON SEQUENCE chats.messages_id_seq TO service_role;
133 |
134 | GRANT ALL ON TABLE chats.rooms TO anon;
135 | GRANT ALL ON TABLE chats.rooms TO authenticated;
136 | GRANT ALL ON TABLE chats.rooms TO service_role;
137 |
138 | GRANT ALL ON SEQUENCE chats.rooms_id_seq TO anon;
139 | GRANT ALL ON SEQUENCE chats.rooms_id_seq TO authenticated;
140 | GRANT ALL ON SEQUENCE chats.rooms_id_seq TO service_role;
141 |
142 | GRANT ALL ON TABLE chats.users TO anon;
143 | GRANT ALL ON TABLE chats.users TO authenticated;
144 | GRANT ALL ON TABLE chats.users TO service_role;
145 |
146 | GRANT USAGE ON SCHEMA chats TO anon, authenticated, service_role;
147 | GRANT ALL ON ALL TABLES IN SCHEMA chats TO anon, authenticated, service_role;
148 | GRANT ALL ON ALL ROUTINES IN SCHEMA chats TO anon, authenticated, service_role;
149 | GRANT ALL ON ALL SEQUENCES IN SCHEMA chats TO anon, authenticated, service_role;
150 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON TABLES TO anon, authenticated, service_role;
151 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON ROUTINES TO anon, authenticated, service_role;
152 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON SEQUENCES TO anon, authenticated, service_role;
153 |
154 | ALTER PUBLICATION supabase_realtime ADD TABLE ONLY chats.messages;
155 |
156 | ALTER PUBLICATION supabase_realtime ADD TABLE ONLY chats.rooms;
157 |
158 | ALTER PUBLICATION supabase_realtime ADD TABLE ONLY chats.users;
--------------------------------------------------------------------------------
/example/utils/sql/02_database_trigger.sql:
--------------------------------------------------------------------------------
1 |
2 | CREATE OR REPLACE FUNCTION chats.handle_new_user()
3 | RETURNS trigger
4 | LANGUAGE 'plpgsql'
5 | COST 100
6 | VOLATILE NOT LEAKPROOF SECURITY DEFINER
7 | SET search_path=public
8 | SET search_path = ''
9 | AS $BODY$
10 | DECLARE
11 | ts_in_milliseconds bigint;
12 | BEGIN
13 | SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds;
14 | insert into chats.users (id, "createdAt", "updatedAt", "lastSeen")
15 | values (new.id, ts_in_milliseconds, ts_in_milliseconds, ts_in_milliseconds);
16 | return new;
17 | end;
18 | $BODY$;
19 |
20 | drop trigger if exists on_auth_user_created on auth.users;
21 | create trigger on_auth_user_created
22 | after insert on auth.users
23 | for each row execute procedure chats.handle_new_user();
24 |
25 |
26 | CREATE OR REPLACE FUNCTION chats.update_last_messages()
27 | RETURNS TRIGGER
28 | SET search_path = ''
29 | AS $$
30 | DECLARE
31 | latest_message jsonb;
32 | ts_in_milliseconds bigint;
33 | BEGIN
34 | SELECT jsonb_build_object(
35 | 'id', id,
36 | 'createdAt', "createdAt",
37 | 'metadata', metadata,
38 | 'duration', duration,
39 | 'mimeType', "mimeType",
40 | 'name', name,
41 | 'remoteId', "remoteId",
42 | 'repliedMessage', "repliedMessage",
43 | 'roomId', "roomId",
44 | 'showStatus', "showStatus",
45 | 'size', size,
46 | 'status', status,
47 | 'type', type,
48 | 'updatedAt', "updatedAt",
49 | 'uri', uri,
50 | 'waveForm', "waveForm",
51 | 'isLoading', "isLoading",
52 | 'height', height,
53 | 'width', width,
54 | 'previewData', "previewData",
55 | 'authorId', "authorId",
56 | 'text', text
57 | )
58 | INTO latest_message
59 | FROM chats.messages
60 | WHERE "roomId" = NEW."roomId"
61 | ORDER BY "createdAt" DESC
62 | LIMIT 1;
63 | IF latest_message IS DISTINCT FROM (SELECT "lastMessages" FROM chats.rooms WHERE id = NEW."roomId") THEN
64 | SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds;
65 | UPDATE chats.rooms
66 | SET "updatedAt" = ts_in_milliseconds,
67 | "lastMessages" = jsonb_build_array(latest_message)
68 | WHERE id = NEW."roomId";
69 | END IF;
70 | RETURN NEW;
71 | END;
72 | $$ LANGUAGE plpgsql;
73 |
74 | drop trigger if exists update_last_messages_trigger on chats.messages;
75 | CREATE TRIGGER update_last_messages_trigger
76 | AFTER INSERT OR UPDATE ON chats.messages
77 | FOR EACH ROW
78 | EXECUTE FUNCTION chats.update_last_messages();
79 |
80 | CREATE OR REPLACE FUNCTION chats.set_message_status_to_sent()
81 | RETURNS TRIGGER
82 | SET search_path = ''
83 | AS $$
84 | BEGIN
85 | NEW.status := 'sent';
86 | RETURN NEW;
87 | END;
88 | $$ LANGUAGE plpgsql;
89 |
90 | drop trigger if exists update_status_before_insert on chats.messages;
91 | CREATE TRIGGER update_status_before_insert
92 | BEFORE INSERT ON chats.messages
93 | FOR EACH ROW EXECUTE FUNCTION chats.set_message_status_to_sent();
94 |
--------------------------------------------------------------------------------
/example/utils/sql/03_database_policy.sql:
--------------------------------------------------------------------------------
1 | DROP POLICY IF EXISTS "chats.users_grant_create" ON chats.users;
2 | DROP POLICY IF EXISTS "chats.users_grant_read" ON chats.users;
3 | DROP POLICY IF EXISTS "chats.users_grant_update" ON chats.users;
4 | DROP POLICY IF EXISTS "chats.users_grant_delete" ON chats.users;
5 |
6 | DROP POLICY IF EXISTS "chats.rooms_grant_create" ON chats.rooms;
7 | DROP POLICY IF EXISTS "chats.rooms_grant_read" ON chats.rooms;
8 | DROP POLICY IF EXISTS "chats.rooms_grant_update" ON chats.rooms;
9 | DROP POLICY IF EXISTS "chats.rooms_grant_delete" ON chats.rooms;
10 |
11 | DROP POLICY IF EXISTS "chats.messages_grant_create" ON chats.messages;
12 | DROP POLICY IF EXISTS "chats.messages_grant_read" ON chats.messages;
13 | DROP POLICY IF EXISTS "chats.messages_grant_update" ON chats.messages;
14 | DROP POLICY IF EXISTS "chats.messages_grant_delete" ON chats.messages;
15 |
16 | CREATE OR REPLACE FUNCTION chats.is_auth()
17 | RETURNS boolean
18 | LANGUAGE 'plpgsql'
19 | COST 100
20 | VOLATILE NOT LEAKPROOF SECURITY INVOKER
21 | SET search_path = ''
22 | AS $BODY$
23 | BEGIN
24 | return auth.uid() IS NOT NULL;
25 | end;
26 | $BODY$;
27 |
28 | CREATE OR REPLACE FUNCTION chats.is_owner(user_id uuid)
29 | RETURNS boolean
30 | LANGUAGE 'plpgsql'
31 | COST 100
32 | VOLATILE NOT LEAKPROOF SECURITY INVOKER
33 | SET search_path = ''
34 | AS $BODY$
35 | BEGIN
36 | return auth.uid() = user_id;
37 | end;
38 | $BODY$;
39 |
40 | CREATE OR REPLACE FUNCTION chats.is_member(members uuid[])
41 | RETURNS boolean
42 | LANGUAGE 'plpgsql'
43 | COST 100
44 | VOLATILE NOT LEAKPROOF SECURITY INVOKER
45 | SET search_path = ''
46 | AS $BODY$
47 | BEGIN
48 | return auth.uid() = ANY(members);
49 | end;
50 | $BODY$;
51 |
52 | CREATE OR REPLACE FUNCTION chats.is_chat_member(room_id bigint)
53 | RETURNS boolean
54 | LANGUAGE 'plpgsql'
55 | COST 100
56 | VOLATILE NOT LEAKPROOF SECURITY INVOKER
57 | SET search_path = ''
58 | AS $BODY$
59 | DECLARE
60 | members uuid[];
61 | BEGIN
62 | SELECT "userIds" INTO members
63 | FROM chats.rooms
64 | WHERE id = room_id;
65 | return chats.is_member(members);
66 | end;
67 | $BODY$;
68 |
69 | CREATE POLICY "chats.users_grant_create"
70 | ON chats.users
71 | AS PERMISSIVE
72 | FOR INSERT
73 | TO public
74 | WITH CHECK (false); -- Created by trigger
75 |
76 | CREATE POLICY "chats.users_grant_read"
77 | ON chats.users
78 | AS PERMISSIVE
79 | FOR SELECT
80 | TO public
81 | USING (chats.is_auth());
82 |
83 | CREATE POLICY "chats.users_grant_update"
84 | ON chats.users
85 | AS PERMISSIVE
86 | FOR UPDATE
87 | TO public
88 | USING (chats.is_auth())
89 | WITH CHECK (chats.is_owner(id));
90 |
91 | CREATE POLICY "chats.users_grant_delete"
92 | ON chats.users
93 | AS PERMISSIVE
94 | FOR DELETE
95 | TO public
96 | USING (false); -- Delete by foreign key
97 |
98 | CREATE POLICY "chats.rooms_grant_create"
99 | ON chats.rooms
100 | AS PERMISSIVE
101 | FOR INSERT
102 | TO public
103 | WITH CHECK (chats.is_auth());
104 |
105 | CREATE POLICY "chats.rooms_grant_read"
106 | ON chats.rooms
107 | AS PERMISSIVE
108 | FOR SELECT
109 | TO public
110 | USING (chats.is_member("userIds"));
111 |
112 | CREATE POLICY "chats.rooms_grant_update"
113 | ON chats.rooms
114 | AS PERMISSIVE
115 | FOR UPDATE
116 | TO public
117 | USING (chats.is_member("userIds"))
118 | WITH CHECK (chats.is_member("userIds"));
119 |
120 | CREATE POLICY "chats.rooms_grant_delete"
121 | ON chats.rooms
122 | AS PERMISSIVE
123 | FOR DELETE
124 | TO public
125 | USING (chats.is_member("userIds"));
126 |
127 | CREATE POLICY "chats.messages_grant_create"
128 | ON chats.messages
129 | AS PERMISSIVE
130 | FOR INSERT
131 | TO public
132 | WITH CHECK (chats.is_chat_member("roomId"));
133 |
134 | CREATE POLICY "chats.messages_grant_read"
135 | ON chats.messages
136 | AS PERMISSIVE
137 | FOR SELECT
138 | TO public
139 | USING (chats.is_chat_member("roomId"));
140 |
141 | CREATE POLICY "chats.messages_grant_update"
142 | ON chats.messages
143 | AS PERMISSIVE
144 | FOR UPDATE
145 | TO public
146 | USING (chats.is_chat_member("roomId"))
147 | WITH CHECK (chats.is_chat_member("roomId"));
148 |
149 | CREATE POLICY "chats.messages_grant_delete"
150 | ON chats.messages
151 | AS PERMISSIVE
152 | FOR DELETE
153 | TO public
154 | USING (chats.is_chat_member("roomId"));
--------------------------------------------------------------------------------
/example/utils/sql/04_storage.sql:
--------------------------------------------------------------------------------
1 | insert into storage.buckets
2 | (id, name)
3 | values
4 | ('chats_assets', 'chats_assets'),
5 | ('chats_user_avatar', 'chats_user_avatar');
6 |
7 | DROP policy IF EXISTS "storage.object_grant_create_auth_chats_assets"
8 | ON storage.objects;
9 | create policy "storage.object_grant_create_auth_chats_assets"
10 | on storage.objects for insert
11 | with check (
12 | bucket_id = 'chats_assets'
13 | and
14 | chats.is_chat_member((storage.foldername(name))[1]::bigint));
15 |
16 | DROP policy IF EXISTS "storage.object_grant_read_auth_chats_assets"
17 | ON storage.objects;
18 | create policy "storage.object_grant_read_auth_chats_assets"
19 | on storage.objects for select
20 | using (
21 | bucket_id = 'chats_assets'
22 | and
23 | chats.is_chat_member((storage.foldername(name))[1]::bigint));
24 |
25 | DROP policy IF EXISTS "storage.object_grant_update_auth_chats_assets"
26 | ON storage.objects;
27 | create policy "storage.object_grant_update_auth_chats_assets"
28 | on storage.objects for update
29 | using (
30 | bucket_id = 'chats_assets'
31 | and
32 | chats.is_chat_member((storage.foldername(name))[1]::bigint))
33 | with check (
34 | bucket_id = 'chats_assets'
35 | and
36 | chats.is_chat_member((storage.foldername(name))[1]::bigint));
37 |
38 | DROP policy IF EXISTS "storage.object_grant_delete_auth_chats_assets"
39 | ON storage.objects;
40 | create policy "storage.object_grant_delete_auth_chats_assets"
41 | on storage.objects for delete
42 | using (
43 | bucket_id = 'chats_assets'
44 | and
45 | chats.is_chat_member((storage.foldername(name))[1]::bigint));
46 |
47 | DROP policy IF EXISTS "storage.object_grant_create_auth_chats_user_avatar"
48 | ON storage.objects;
49 | create policy "storage.object_grant_create_auth_chats_user_avatar"
50 | on storage.objects for insert
51 | with check (
52 | bucket_id = 'chats_user_avatar'
53 | and
54 | chats.is_owner((storage.foldername(name))[1]::uuid));
55 |
56 | DROP policy IF EXISTS "storage.object_grant_read_auth_chats_user_avatar"
57 | ON storage.objects;
58 | create policy "storage.object_grant_read_auth_chats_user_avatar"
59 | on storage.objects for select
60 | using (
61 | bucket_id = 'chats_user_avatar'
62 | and
63 | chats.is_auth());
64 |
65 | DROP policy IF EXISTS "storage.object_grant_update_auth_chats_user_avatar"
66 | ON storage.objects;
67 | create policy "storage.object_grant_update_auth_chats_user_avatar"
68 | on storage.objects for update
69 | using (
70 | bucket_id = 'chats_user_avatar'
71 | and
72 | chats.is_owner((storage.foldername(name))[1]::uuid))
73 | with check (
74 | bucket_id = 'chats_user_avatar'
75 | and
76 | chats.is_owner((storage.foldername(name))[1]::uuid));
77 |
78 | DROP policy IF EXISTS "storage.object_grant_delete_auth_chats_user_avatar"
79 | ON storage.objects;
80 | create policy "storage.object_grant_delete_auth_chats_user_avatar"
81 | on storage.objects for delete
82 | using (
83 | bucket_id = 'chats_user_avatar'
84 | and
85 | chats.is_owner((storage.foldername(name))[1]::uuid));
86 |
--------------------------------------------------------------------------------
/example/utils/sql/05_database_view.sql:
--------------------------------------------------------------------------------
1 | DROP VIEW IF EXISTS chats.messages_l;
2 | DROP VIEW IF EXISTS chats.rooms_l;
3 |
4 | create or replace view chats.rooms_l
5 | with (security_invoker='on') as
6 | select r.id,
7 | r."imageUrl",
8 | r.metadata,
9 | case
10 | when r.type = 'direct' and auth.uid() is not null then
11 | (select coalesce(u."firstName", '') || ' ' || coalesce(u."lastName", '')
12 | from chats.users u
13 | where u.id = any (r."userIds")
14 | and u.id <> auth.uid()
15 | limit 1)
16 | else
17 | r.name
18 | end as name,
19 | r.type,
20 | r."userIds",
21 | r."lastMessages",
22 | r."userRoles",
23 | r."createdAt",
24 | r."updatedAt",
25 | (select jsonb_agg(to_jsonb(u))
26 | from chats.users u
27 | where u.id = any (r."userIds")) as users
28 | from chats.rooms r;
29 |
30 |
31 | create or replace view chats.messages_l
32 | with (security_invoker='on') as
33 | select m.id,
34 | m."createdAt",
35 | m.metadata,
36 | m.duration,
37 | m."mimeType",
38 | m.name,
39 | m."remoteId",
40 | m."repliedMessage",
41 | m."roomId",
42 | m."showStatus",
43 | m.size,
44 | m.status,
45 | m.type,
46 | m."updatedAt",
47 | m.uri,
48 | m."waveForm",
49 | m."isLoading",
50 | m.height,
51 | m.width,
52 | m."previewData",
53 | m."authorId",
54 | m.text,
55 | to_jsonb(u) as author,
56 | to_jsonb(r) as room
57 | from chats.messages m
58 | left join chats.users u on u.id = m."authorId"
59 | left join chats.rooms_l r on r.id = m."roomId";
60 |
--------------------------------------------------------------------------------
/example/utils/sql/99_database_schema_permission.sql:
--------------------------------------------------------------------------------
1 | GRANT USAGE ON SCHEMA chats TO anon, authenticated, service_role;
2 | GRANT ALL ON ALL TABLES IN SCHEMA chats TO anon, authenticated, service_role;
3 | GRANT ALL ON ALL ROUTINES IN SCHEMA chats TO anon, authenticated, service_role;
4 | GRANT ALL ON ALL SEQUENCES IN SCHEMA chats TO anon, authenticated, service_role;
5 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON TABLES TO anon, authenticated, service_role;
6 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON ROUTINES TO anon, authenticated, service_role;
7 | ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA chats GRANT ALL ON SEQUENCES TO anon, authenticated, service_role;
8 |
--------------------------------------------------------------------------------
/example/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/web/favicon.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/example/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | example
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/example/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "short_name": "example",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/example/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/example/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Project-level configuration.
2 | cmake_minimum_required(VERSION 3.14)
3 | project(example LANGUAGES CXX)
4 |
5 | # The name of the executable created for the application. Change this to change
6 | # the on-disk name of your application.
7 | set(BINARY_NAME "example")
8 |
9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
10 | # versions of CMake.
11 | cmake_policy(SET CMP0063 NEW)
12 |
13 | # Define build configuration option.
14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
15 | if(IS_MULTICONFIG)
16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
17 | CACHE STRING "" FORCE)
18 | else()
19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
20 | set(CMAKE_BUILD_TYPE "Debug" CACHE
21 | STRING "Flutter build mode" FORCE)
22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
23 | "Debug" "Profile" "Release")
24 | endif()
25 | endif()
26 | # Define settings for the Profile build mode.
27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
31 |
32 | # Use Unicode for all projects.
33 | add_definitions(-DUNICODE -D_UNICODE)
34 |
35 | # Compilation settings that should be applied to most targets.
36 | #
37 | # Be cautious about adding new options here, as plugins use this function by
38 | # default. In most cases, you should add new options to specific targets instead
39 | # of modifying this function.
40 | function(APPLY_STANDARD_SETTINGS TARGET)
41 | target_compile_features(${TARGET} PUBLIC cxx_std_17)
42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
43 | target_compile_options(${TARGET} PRIVATE /EHsc)
44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
46 | endfunction()
47 |
48 | # Flutter library and tool build rules.
49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
50 | add_subdirectory(${FLUTTER_MANAGED_DIR})
51 |
52 | # Application build; see runner/CMakeLists.txt.
53 | add_subdirectory("runner")
54 |
55 |
56 | # Generated plugin build rules, which manage building the plugins and adding
57 | # them to the application.
58 | include(flutter/generated_plugins.cmake)
59 |
60 |
61 | # === Installation ===
62 | # Support files are copied into place next to the executable, so that it can
63 | # run in place. This is done instead of making a separate bundle (as on Linux)
64 | # so that building and running from within Visual Studio will work.
65 | set(BUILD_BUNDLE_DIR "$")
66 | # Make the "install" step default, as it's required to run.
67 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
68 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
69 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
70 | endif()
71 |
72 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
73 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
74 |
75 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
76 | COMPONENT Runtime)
77 |
78 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
79 | COMPONENT Runtime)
80 |
81 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
82 | COMPONENT Runtime)
83 |
84 | if(PLUGIN_BUNDLED_LIBRARIES)
85 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
86 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
87 | COMPONENT Runtime)
88 | endif()
89 |
90 | # Fully re-copy the assets directory on each build to avoid having stale files
91 | # from a previous install.
92 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
93 | install(CODE "
94 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
95 | " COMPONENT Runtime)
96 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
97 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
98 |
99 | # Install the AOT library on non-Debug builds only.
100 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
101 | CONFIGURATIONS Profile;Release
102 | COMPONENT Runtime)
103 |
--------------------------------------------------------------------------------
/example/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.14)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
12 |
13 | # Set fallback configurations for older versions of the flutter tool.
14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
15 | set(FLUTTER_TARGET_PLATFORM "windows-x64")
16 | endif()
17 |
18 | # === Flutter Library ===
19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
20 |
21 | # Published to parent scope for install step.
22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
26 |
27 | list(APPEND FLUTTER_LIBRARY_HEADERS
28 | "flutter_export.h"
29 | "flutter_windows.h"
30 | "flutter_messenger.h"
31 | "flutter_plugin_registrar.h"
32 | "flutter_texture_registrar.h"
33 | )
34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
35 | add_library(flutter INTERFACE)
36 | target_include_directories(flutter INTERFACE
37 | "${EPHEMERAL_DIR}"
38 | )
39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
40 | add_dependencies(flutter flutter_assemble)
41 |
42 | # === Wrapper ===
43 | list(APPEND CPP_WRAPPER_SOURCES_CORE
44 | "core_implementations.cc"
45 | "standard_codec.cc"
46 | )
47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
49 | "plugin_registrar.cc"
50 | )
51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
52 | list(APPEND CPP_WRAPPER_SOURCES_APP
53 | "flutter_engine.cc"
54 | "flutter_view_controller.cc"
55 | )
56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
57 |
58 | # Wrapper sources needed for a plugin.
59 | add_library(flutter_wrapper_plugin STATIC
60 | ${CPP_WRAPPER_SOURCES_CORE}
61 | ${CPP_WRAPPER_SOURCES_PLUGIN}
62 | )
63 | apply_standard_settings(flutter_wrapper_plugin)
64 | set_target_properties(flutter_wrapper_plugin PROPERTIES
65 | POSITION_INDEPENDENT_CODE ON)
66 | set_target_properties(flutter_wrapper_plugin PROPERTIES
67 | CXX_VISIBILITY_PRESET hidden)
68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
69 | target_include_directories(flutter_wrapper_plugin PUBLIC
70 | "${WRAPPER_ROOT}/include"
71 | )
72 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
73 |
74 | # Wrapper sources needed for the runner.
75 | add_library(flutter_wrapper_app STATIC
76 | ${CPP_WRAPPER_SOURCES_CORE}
77 | ${CPP_WRAPPER_SOURCES_APP}
78 | )
79 | apply_standard_settings(flutter_wrapper_app)
80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
81 | target_include_directories(flutter_wrapper_app PUBLIC
82 | "${WRAPPER_ROOT}/include"
83 | )
84 | add_dependencies(flutter_wrapper_app flutter_assemble)
85 |
86 | # === Flutter tool backend ===
87 | # _phony_ is a non-existent file to force this command to run every time,
88 | # since currently there's no way to get a full input/output list from the
89 | # flutter tool.
90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
92 | add_custom_command(
93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
95 | ${CPP_WRAPPER_SOURCES_APP}
96 | ${PHONY_OUTPUT}
97 | COMMAND ${CMAKE_COMMAND} -E env
98 | ${FLUTTER_TOOL_ENVIRONMENT}
99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
100 | ${FLUTTER_TARGET_PLATFORM} $
101 | VERBATIM
102 | )
103 | add_custom_target(flutter_assemble DEPENDS
104 | "${FLUTTER_LIBRARY}"
105 | ${FLUTTER_LIBRARY_HEADERS}
106 | ${CPP_WRAPPER_SOURCES_CORE}
107 | ${CPP_WRAPPER_SOURCES_PLUGIN}
108 | ${CPP_WRAPPER_SOURCES_APP}
109 | )
110 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void RegisterPlugins(flutter::PluginRegistry* registry) {
15 | AppLinksPluginCApiRegisterWithRegistrar(
16 | registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
17 | FileSaverPluginRegisterWithRegistrar(
18 | registry->GetRegistrarForPlugin("FileSaverPlugin"));
19 | FileSelectorWindowsRegisterWithRegistrar(
20 | registry->GetRegistrarForPlugin("FileSelectorWindows"));
21 | UrlLauncherWindowsRegisterWithRegistrar(
22 | registry->GetRegistrarForPlugin("UrlLauncherWindows"));
23 | }
24 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | app_links
7 | file_saver
8 | file_selector_windows
9 | url_launcher_windows
10 | )
11 |
12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 | )
14 |
15 | set(PLUGIN_BUNDLED_LIBRARIES)
16 |
17 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
22 | endforeach(plugin)
23 |
24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
27 | endforeach(ffi_plugin)
28 |
--------------------------------------------------------------------------------
/example/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(runner LANGUAGES CXX)
3 |
4 | # Define the application target. To change its name, change BINARY_NAME in the
5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 | # work.
7 | #
8 | # Any new source files that you add to the application should be added here.
9 | add_executable(${BINARY_NAME} WIN32
10 | "flutter_window.cpp"
11 | "main.cpp"
12 | "utils.cpp"
13 | "win32_window.cpp"
14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 | "Runner.rc"
16 | "runner.exe.manifest"
17 | )
18 |
19 | # Apply the standard set of build settings. This can be removed for applications
20 | # that need different build settings.
21 | apply_standard_settings(${BINARY_NAME})
22 |
23 | # Add preprocessor definitions for the build version.
24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 |
30 | # Disable Windows macros that collide with C++ standard library functions.
31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 |
33 | # Add dependency libraries and include directories. Add any application-specific
34 | # dependencies here.
35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
38 |
39 | # Run the Flutter tool portions of the build. This must not be removed.
40 | add_dependencies(${BINARY_NAME} flutter_assemble)
41 |
--------------------------------------------------------------------------------
/example/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0,0
67 | #endif
68 |
69 | #if defined(FLUTTER_VERSION)
70 | #define VERSION_AS_STRING FLUTTER_VERSION
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "com." "\0"
93 | VALUE "FileDescription", "example" "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "example" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2023 com.. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "example.exe" "\0"
98 | VALUE "ProductName", "example" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 |
30 | flutter_controller_->engine()->SetNextFrameCallback([&]() {
31 | this->Show();
32 | });
33 |
34 | // Flutter can complete the first frame before the "show window" callback is
35 | // registered. The following call ensures a frame is pending to ensure the
36 | // window is shown. It is a no-op if the first frame hasn't completed yet.
37 | flutter_controller_->ForceRedraw();
38 |
39 | return true;
40 | }
41 |
42 | void FlutterWindow::OnDestroy() {
43 | if (flutter_controller_) {
44 | flutter_controller_ = nullptr;
45 | }
46 |
47 | Win32Window::OnDestroy();
48 | }
49 |
50 | LRESULT
51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
52 | WPARAM const wparam,
53 | LPARAM const lparam) noexcept {
54 | // Give Flutter, including plugins, an opportunity to handle window messages.
55 | if (flutter_controller_) {
56 | std::optional result =
57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
58 | lparam);
59 | if (result) {
60 | return *result;
61 | }
62 | }
63 |
64 | switch (message) {
65 | case WM_FONTCHANGE:
66 | flutter_controller_->engine()->ReloadSystemFonts();
67 | break;
68 | }
69 |
70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
71 | }
72 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/example/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.Create(L"example", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/example/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/example/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/insideapp-srl/flutter_supabase_chat_core/5b767822714b9d5876df8fc2f77de1badeb02669/example/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/example/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr)
51 | -1; // remove the trailing null character
52 | int input_length = (int)wcslen(utf16_string);
53 | std::string utf8_string;
54 | if (target_length <= 0 || target_length > utf8_string.max_size()) {
55 | return utf8_string;
56 | }
57 | utf8_string.resize(target_length);
58 | int converted_length = ::WideCharToMultiByte(
59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
60 | input_length, utf8_string.data(), target_length, nullptr, nullptr);
61 | if (converted_length == 0) {
62 | return std::string();
63 | }
64 | return utf8_string;
65 | }
66 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/example/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_WIN32_WINDOW_H_
2 | #define RUNNER_WIN32_WINDOW_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 | public:
15 | struct Point {
16 | unsigned int x;
17 | unsigned int y;
18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 | };
20 |
21 | struct Size {
22 | unsigned int width;
23 | unsigned int height;
24 | Size(unsigned int width, unsigned int height)
25 | : width(width), height(height) {}
26 | };
27 |
28 | Win32Window();
29 | virtual ~Win32Window();
30 |
31 | // Creates a win32 window with |title| that is positioned and sized using
32 | // |origin| and |size|. New windows are created on the default monitor. Window
33 | // sizes are specified to the OS in physical pixels, hence to ensure a
34 | // consistent size this function will scale the inputted width and height as
35 | // as appropriate for the default monitor. The window is invisible until
36 | // |Show| is called. Returns true if the window was created successfully.
37 | bool Create(const std::wstring& title, const Point& origin, const Size& size);
38 |
39 | // Show the current window. Returns true if the window was successfully shown.
40 | bool Show();
41 |
42 | // Release OS resources associated with window.
43 | void Destroy();
44 |
45 | // Inserts |content| into the window tree.
46 | void SetChildContent(HWND content);
47 |
48 | // Returns the backing Window handle to enable clients to set icon and other
49 | // window properties. Returns nullptr if the window has been destroyed.
50 | HWND GetHandle();
51 |
52 | // If true, closing this window will quit the application.
53 | void SetQuitOnClose(bool quit_on_close);
54 |
55 | // Return a RECT representing the bounds of the current client area.
56 | RECT GetClientArea();
57 |
58 | protected:
59 | // Processes and route salient window messages for mouse handling,
60 | // size change and DPI. Delegates handling of these to member overloads that
61 | // inheriting classes can handle.
62 | virtual LRESULT MessageHandler(HWND window,
63 | UINT const message,
64 | WPARAM const wparam,
65 | LPARAM const lparam) noexcept;
66 |
67 | // Called when CreateAndShow is called, allowing subclass window-related
68 | // setup. Subclasses should return false if setup fails.
69 | virtual bool OnCreate();
70 |
71 | // Called when Destroy is called.
72 | virtual void OnDestroy();
73 |
74 | private:
75 | friend class WindowClassRegistrar;
76 |
77 | // OS callback called by message pump. Handles the WM_NCCREATE message which
78 | // is passed when the non-client area is being created and enables automatic
79 | // non-client DPI scaling so that the non-client area automatically
80 | // responds to changes in DPI. All other messages are handled by
81 | // MessageHandler.
82 | static LRESULT CALLBACK WndProc(HWND const window,
83 | UINT const message,
84 | WPARAM const wparam,
85 | LPARAM const lparam) noexcept;
86 |
87 | // Retrieves a class instance pointer for |window|
88 | static Win32Window* GetThisFromHandle(HWND const window) noexcept;
89 |
90 | // Update the window frame's theme to match the system theme.
91 | static void UpdateTheme(HWND const window);
92 |
93 | bool quit_on_close_ = false;
94 |
95 | // window handle for top level window.
96 | HWND window_handle_ = nullptr;
97 |
98 | // window handle for hosted content.
99 | HWND child_content_ = nullptr;
100 | };
101 |
102 | #endif // RUNNER_WIN32_WINDOW_H_
103 |
--------------------------------------------------------------------------------
/lib/flutter_supabase_chat_core.dart:
--------------------------------------------------------------------------------
1 | library;
2 |
3 | export 'src/class/supabase_chat_controller.dart';
4 | export 'src/class/supabase_chat_core.dart';
5 | export 'src/class/supabase_chat_core_config.dart';
6 | export 'src/class/upload_asset_result.dart';
7 | export 'src/class/user_online_status.dart';
8 | export 'src/util.dart';
9 | export 'src/widgets/user_online_status.dart';
10 | export 'src/widgets/user_status_observer.dart';
11 |
--------------------------------------------------------------------------------
/lib/src/class/supabase_chat_core_config.dart:
--------------------------------------------------------------------------------
1 | import 'package:meta/meta.dart';
2 |
3 | /// Class that represents the chat config. Can be used for setting custom names
4 | /// for rooms and users collections. Call [SupabaseChatCore.instance.setConfig]
5 | /// before doing anything else with [SupabaseChatCore.instance] if you want to
6 | /// change the default collection names. When using custom names don't forget
7 | /// to update your security rules and indexes.
8 | @immutable
9 | class SupabaseChatCoreConfig {
10 | const SupabaseChatCoreConfig(
11 | this.schema,
12 | this.roomsTableName,
13 | this.roomsViewName,
14 | this.messagesTableName,
15 | this.messagesViewName,
16 | this.usersTableName,
17 | this.realtimeOnlineUserPrefixChannel,
18 | this.realtimeChatTypingUserPrefixChannel,
19 | this.chatAssetsBucket,
20 | );
21 |
22 | /// Property to set database schema name.
23 | final String schema;
24 |
25 | /// Property to set rooms table name.
26 | final String roomsTableName;
27 |
28 | /// Property to set rooms table view name.
29 | final String roomsViewName;
30 |
31 | /// Property to set messages table name.
32 | final String messagesTableName;
33 |
34 | /// Property to set messages view name.
35 | final String messagesViewName;
36 |
37 | /// Property to set users table name.
38 | final String usersTableName;
39 |
40 | /// Property to set online users realtime channel.
41 | final String realtimeOnlineUserPrefixChannel;
42 |
43 | /// Property to set users typing in room realtime channel.
44 | final String realtimeChatTypingUserPrefixChannel;
45 |
46 | /// Property to set chat assets bucket.
47 | final String chatAssetsBucket;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/src/class/upload_asset_result.dart:
--------------------------------------------------------------------------------
1 | class UploadAssetResult {
2 | final String url;
3 | final String? mimeType;
4 |
5 | UploadAssetResult({
6 | required this.url,
7 | required this.mimeType,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/class/user_online_status.dart:
--------------------------------------------------------------------------------
1 | enum UserOnlineStatus {
2 | online,
3 | offline,
4 | }
5 |
--------------------------------------------------------------------------------
/lib/src/util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
2 | import 'package:supabase_flutter/supabase_flutter.dart';
3 |
4 | /// Extension with one [toShortString] method.
5 | extension RoleToShortString on types.Role {
6 | /// Converts enum to the string equal to enum's name.
7 | String toShortString() => toString().split('.').last;
8 | }
9 |
10 | /// Extension with one [toShortString] method.
11 | extension RoomTypeToShortString on types.RoomType {
12 | /// Converts enum to the string equal to enum's name.
13 | String toShortString() => toString().split('.').last;
14 | }
15 |
16 | /// Fetches user from Firebase and returns a promise.
17 | Future