@@ -1,24 +0,0 @@
|
||||
name: Flutter Analyze
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: subosito/flutter-action@v1
|
||||
with:
|
||||
channel: 'beta'
|
||||
- run: flutter pub get
|
||||
|
||||
- name: 'Flutter Format Check'
|
||||
run: flutter format --set-exit-if-changed --dry-run .
|
||||
|
||||
- run: flutter analyze
|
||||
@@ -1,35 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Flutter action
|
||||
uses: subosito/[email protected]
|
||||
with:
|
||||
channel: 'stable'
|
||||
- name: Get dependencies
|
||||
run: flutter pub get
|
||||
- name: Coverage fix
|
||||
run: |
|
||||
file=test/coverage_helper_test.dart
|
||||
echo "// Helper file to make coverage work for all dart files\n" > $file
|
||||
echo "// ignore_for_file: unused_import" >> $file
|
||||
find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file
|
||||
echo "" >> $file
|
||||
echo "void main(){}" >> $file
|
||||
cat $file
|
||||
- name: Run tests
|
||||
run: flutter test --coverage
|
||||
- name: Codecov
|
||||
run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BRANCH=$1
|
||||
|
||||
if [ "$BRANCH" == "dev" ]
|
||||
then
|
||||
# TODO Flutter dev branch is currently broken so we're unable to test MacOS.
|
||||
echo "TODO: Skipping macOS testing due to Flutter dev branch issue. Switching branch to stable."
|
||||
BRANCH=stable
|
||||
fi
|
||||
|
||||
git clone https://github.com/flutter/flutter.git --depth 1 -b $BRANCH _flutter
|
||||
echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin"
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
flutter pub global activate melos 0.4.0+1
|
||||
echo "::add-path::$HOME/.pub-cache/bin"
|
||||
echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin"
|
||||
echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin"
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
if [[ $(git ls-files --modified) ]]; then
|
||||
echo ""
|
||||
echo ""
|
||||
echo "These files are not formatted correctly:"
|
||||
for f in $(git ls-files --modified); do
|
||||
echo ""
|
||||
echo ""
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo "$f"
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo ""
|
||||
git --no-pager diff --unified=0 --minimal $f
|
||||
echo ""
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo ""
|
||||
echo ""
|
||||
done
|
||||
if [[ $GITHUB_WORKFLOW ]]; then
|
||||
git checkout . > /dev/null 2>&1
|
||||
fi
|
||||
echo ""
|
||||
echo "❌ Some files are incorrectly formatted, see above output."
|
||||
echo ""
|
||||
echo "To fix these locally, run: 'melos run format'."
|
||||
exit 1
|
||||
else
|
||||
echo ""
|
||||
echo "✅ All files are formatted correctly."
|
||||
fi
|
||||
@@ -0,0 +1,103 @@
|
||||
name: stream_flutter_workflow
|
||||
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Install Flutter'
|
||||
run: ./.github/workflows/scripts/install-flutter.sh stable
|
||||
- name: 'Install Tools'
|
||||
run: |
|
||||
./.github/workflows/scripts/install-tools.sh
|
||||
flutter pub global activate tuneup
|
||||
- name: 'Bootstrap Workspace'
|
||||
run: melos bootstrap
|
||||
- name: 'Dart Analyze'
|
||||
run: |
|
||||
melos exec -c 3 -- \
|
||||
tuneup check
|
||||
- name: 'Pub Check'
|
||||
run: |
|
||||
melos exec -c 1 --no-private --ignore="*example*" -- \
|
||||
pub publish --dry-run
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Install Flutter'
|
||||
run: ./.github/workflows/scripts/install-flutter.sh stable
|
||||
- name: 'Install Tools'
|
||||
run: |
|
||||
./.github/workflows/scripts/install-tools.sh
|
||||
curl -sL https://github.com/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar -o $HOME/google-java-format.jar
|
||||
- name: 'Bootstrap Workspace'
|
||||
run: melos bootstrap
|
||||
- name: 'Dart'
|
||||
run: |
|
||||
melos exec -c 1 -- \
|
||||
flutter format .
|
||||
./.github/workflows/scripts/validate-formatting.sh
|
||||
- name: 'Objective-C'
|
||||
if: ${{ success() || failure() }}
|
||||
run: |
|
||||
melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \
|
||||
find . -maxdepth 3 -name "*.h" -o -name "*.m" -print0 \| xargs -0 clang-format -i --style=Google --verbose
|
||||
./.github/workflows/scripts/validate-formatting.sh
|
||||
- name: 'Java'
|
||||
if: ${{ success() || failure() }}
|
||||
run: |
|
||||
melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \
|
||||
find . -maxdepth 12 -name "*.java" -print0 \| xargs -0 java -jar $HOME/google-java-format.jar --replace
|
||||
./.github/workflows/scripts/validate-formatting.sh
|
||||
|
||||
test_dart:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Install Flutter'
|
||||
run: ./.github/workflows/scripts/install-flutter.sh stable
|
||||
- name: 'Install Tools'
|
||||
run: ./.github/workflows/scripts/install-tools.sh
|
||||
- name: 'Bootstrap Workspace'
|
||||
run: melos bootstrap
|
||||
- name: 'Flutter Test'
|
||||
run: cd packages/stream_chat && flutter pub run test
|
||||
|
||||
test_flutter:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Install Flutter'
|
||||
run: ./.github/workflows/scripts/install-flutter.sh stable
|
||||
- name: 'Install Tools'
|
||||
run: ./.github/workflows/scripts/install-tools.sh
|
||||
- name: 'Bootstrap Workspace'
|
||||
run: melos bootstrap
|
||||
- name: 'Flutter Test'
|
||||
run: |
|
||||
melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \
|
||||
flutter test
|
||||
@@ -1,64 +1,53 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
coverage/
|
||||
coverage_helper_test.dart
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Exceptions to above rules.
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
|
||||
# Files and directories created by pub
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
flutter_export_environment.sh
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
examples/all_plugins/pubspec.yaml
|
||||
|
||||
# Avoid committing generated Javascript files:
|
||||
*.dart.js
|
||||
*.info.json # Produced by the --dump-info flag.
|
||||
*.js # When generated by dart2js. Don't specify *.js if your
|
||||
# project includes source files written in JavaScript.
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
Podfile
|
||||
Podfile.lock
|
||||
Pods/
|
||||
.symlinks/
|
||||
**/Flutter/App.framework/
|
||||
**/Flutter/ephemeral/
|
||||
**/Flutter/Flutter.framework/
|
||||
**/Flutter/Generated.xcconfig
|
||||
**/Flutter/flutter_assets/
|
||||
|
||||
fvm
|
||||
google-services.json
|
||||
example/ios/dist
|
||||
ServiceDefinitions.json
|
||||
xcuserdata/
|
||||
**/DerivedData/
|
||||
|
||||
local.properties
|
||||
keystore.properties
|
||||
.gradle/
|
||||
gradlew
|
||||
gradlew.bat
|
||||
gradle-wrapper.jar
|
||||
.flutter-plugins-dependencies
|
||||
*.iml
|
||||
|
||||
generated_plugin_registrant.dart
|
||||
GeneratedPluginRegistrant.h
|
||||
GeneratedPluginRegistrant.m
|
||||
GeneratedPluginRegistrant.java
|
||||
GeneratedPluginRegistrant.swift
|
||||
build/
|
||||
.flutter-plugins
|
||||
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
/.fvm
|
||||
|
||||
.melos_tool/
|
||||
/packages/flutter_widgets/example/ios/Flutter/.last_build_id
|
||||
/packages/dart_client/example/ios/Flutter/.last_build_id
|
||||
/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj
|
||||
|
||||
@@ -1,169 +1,59 @@
|
||||
# Official Flutter SDK for [Stream Chat](https://getstream.io/chat/)
|
||||
# Stream Chat Dart
|
||||
|
||||
<p align="center">
|
||||
<a href="https://getstream.io/tutorials/ios-chat/"><img src="https://i.imgur.com/L4Mj8S2.png" alt="Flutter Chat" width="60%" /></a>
|
||||
</p>
|
||||

|
||||
|
||||
> The official Flutter components for Stream Chat, a service for
|
||||
> building chat applications.
|
||||
This repository contains code for our [Dart](https://dart.dev/) and [Flutter](https://flutter.dev/) chat clients.
|
||||
|
||||
[](https://pub.dartlang.org/packages/stream_chat_flutter)
|
||||

|
||||
[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||

|
||||
<img align="right" src="https://getstream.imgix.net/images/ios-chat-tutorial/iphone_chat_art@1x.png?auto=format,enhance" width="50%" />
|
||||
Stream allows developers to rapidly deploy scalable feeds and chat messaging with an industry leading 99.999% uptime SLA guarantee.
|
||||
|
||||
**Quick Links**
|
||||
## Structure
|
||||
Stream Chat Dart is a monorepo built using [Melos](https://docs.page/invertase/melos). Individual packages can be found in the `packages` directory while configuration and top level commands can be found in `melos.yaml`.
|
||||
|
||||
- [Register](https://getstream.io/chat/trial/) to get an API key for Stream Chat
|
||||
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
|
||||
To get started, run `bootstrap` after cloning the project.
|
||||
|
||||
## Flutter Chat Tutorial
|
||||
|
||||
The best place to start is the [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/).
|
||||
It teaches you how to use this SDK and also shows how to make frequently required changes.
|
||||
|
||||
## Example App
|
||||
|
||||
This repo includes a fully functional example app with setup instructions.
|
||||
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder.
|
||||
|
||||
## Add dependency
|
||||
Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_chat_flutter)
|
||||
```yaml
|
||||
dependencies:
|
||||
stream_chat_flutter: ^latest_version
|
||||
```shell
|
||||
melos bootstrap
|
||||
```
|
||||
|
||||
You should then run `flutter packages get`
|
||||
## Available Commands
|
||||
### Analyze
|
||||
> Requires `tuneup` to be activated globally. Please see https://pub.dev/packages/tuneup
|
||||
```shell
|
||||
melos run analyze
|
||||
```
|
||||
|
||||
### Android
|
||||
### Pub Lint
|
||||
Runs pub publish with ``--dry-run``
|
||||
```shell
|
||||
melos run lint:pub
|
||||
```
|
||||
|
||||
All set ✅
|
||||
### Build iOS
|
||||
Builds iOS examples without codesign
|
||||
```shell
|
||||
melos run build:examples:ios
|
||||
```
|
||||
|
||||
### iOS
|
||||
### Build APK
|
||||
Builds an Android APK for examples
|
||||
```shell
|
||||
melos run build:examples:android
|
||||
```
|
||||
|
||||
The library uses [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) to pick
|
||||
files from the os.
|
||||
Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements.
|
||||
### Build MACOS
|
||||
Builds MacOs for all examples
|
||||
```shell
|
||||
melos run build:examples:macos
|
||||
```
|
||||
|
||||
We also use [video_player](https://pub.dev/packages/video_player) to reproduce videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements.
|
||||
### Test
|
||||
Runs `flutter test` on all packages
|
||||
```shell
|
||||
melos run test
|
||||
```
|
||||
|
||||
To pick images from the camera, we use the [image_picker](https://pub.dev/packages/image_picker) plugin.
|
||||
Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
It may happen that you have some problems building the app.
|
||||
If it seems related to the [flutter file picker plugin](https://github.com/miguelpruivo/flutter_file_picker) make sure to check [this page](https://github.com/miguelpruivo/flutter_file_picker/wiki/Troubleshooting)
|
||||
|
||||
## Docs
|
||||
|
||||
### Business logic components
|
||||
|
||||
We provide 3 Widgets dedicated to business logic and state management:
|
||||
|
||||
- [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html)
|
||||
- [StreamChannel](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannel-class.html)
|
||||
- [ChannelsBloc](https://pub.dev/documentation/stream_chat_flutter/0.2.0-alpha+2/stream_chat_flutter/ChannelsBloc-class.html)
|
||||
|
||||
### UI Components
|
||||
|
||||
These are the available Widgets that you can use to build your application UI.
|
||||
Every widget uses the `StreamChat` or `StreamChannel` widgets to manage the state and communicate with Stream services.
|
||||
|
||||
- [ChannelHeader](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelHeader-class.html)
|
||||
- [ChannelImage](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelImage-class.html)
|
||||
- [ChannelListView](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelListView-class.html)
|
||||
- [ChannelName](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelName-class.html)
|
||||
- [ChannelPreview](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ChannelPreview-class.html)
|
||||
- [MessageInput](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageInput-class.html)
|
||||
- [MessageListView](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageListView-class.html)
|
||||
- [MessageWidget](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/MessageWidget-class.html)
|
||||
- [StreamChatTheme](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChatTheme-class.html)
|
||||
- [ThreadHeader](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/ThreadHeader-class.html)
|
||||
- ...
|
||||
|
||||
### Customizing styles
|
||||
|
||||
The Flutter SDK comes with a fully designed set of widgets that you can customize to fit with your application style and typography.
|
||||
Changing the theme of Chat widgets works in a very similar way that `MaterialApp` and `Theme` do.
|
||||
|
||||
Out of the box, all chat widgets use their default styling, and there are two ways to change the styling:
|
||||
|
||||
1. Initialize the `StreamChatTheme` from your existing `MaterialApp` style
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
final Client client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ThemeData(
|
||||
primarySwatch: Colors.green,
|
||||
);
|
||||
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
streamChatThemeData: StreamChatThemeData.fromTheme(theme),
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Construct a custom theme and provide all the customizations needed
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
final Client client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ThemeData(
|
||||
primarySwatch: Colors.green,
|
||||
);
|
||||
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith(
|
||||
ownMessageTheme: MessageTheme(
|
||||
messageBackgroundColor: Colors.black,
|
||||
messageText: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
avatarTheme: AvatarTheme(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Offline storage
|
||||
|
||||
By default the library saves information about channels and messages in a SQLite DB.
|
||||
|
||||
Set the property `persistenceEnabled` to false if you don't want to use the offline storage.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome code changes that improve this library or fix a problem,
|
||||
please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github.
|
||||
We are pleased to merge your code into the official repository.
|
||||
Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first.
|
||||
See our license file for more details.
|
||||
### Test Web
|
||||
Runs `flutter test --platform=chrome` on all packages
|
||||
```shell
|
||||
melos run test:web
|
||||
```
|
||||
|
||||
@@ -1,61 +1,13 @@
|
||||
include: package:pedantic/analysis_options.yaml
|
||||
include: package:pedantic/analysis_options.1.9.0.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- lib/**/*.g.dart
|
||||
- example/**
|
||||
# Ignore generated files
|
||||
- '**/*.g.dart'
|
||||
- 'lib/src/generated/*.dart'
|
||||
|
||||
linter:
|
||||
rules:
|
||||
# these rules are documented on and in the same order as
|
||||
# the Dart Lint rules page to make maintenance easier
|
||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||
# - always_declare_return_types
|
||||
# - always_specify_types
|
||||
# - annotate_overrides
|
||||
# - avoid_as
|
||||
- avoid_empty_else
|
||||
- avoid_init_to_null
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_web_libraries_in_flutter
|
||||
- await_only_futures
|
||||
- camel_case_types
|
||||
- cancel_subscriptions
|
||||
- close_sinks
|
||||
# - comment_references # we do not presume as to what people want to reference in their dartdocs
|
||||
# - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
|
||||
- control_flow_in_finally
|
||||
- empty_constructor_bodies
|
||||
- empty_statements
|
||||
- hash_and_equals
|
||||
- implementation_imports
|
||||
# - invariant_booleans
|
||||
# - iterable_contains_unrelated_type
|
||||
- library_names
|
||||
# - library_prefixes
|
||||
# - list_remove_unrelated_type
|
||||
# - literal_only_boolean_expressions
|
||||
- non_constant_identifier_names
|
||||
# - one_member_abstracts
|
||||
# - only_throw_errors
|
||||
# - overridden_fields
|
||||
# - package_api_docs
|
||||
- package_names
|
||||
- package_prefixed_library_names
|
||||
- prefer_is_not_empty
|
||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||
- public_member_api_docs
|
||||
- slash_for_doc_comments
|
||||
# - sort_constructors_first
|
||||
# - sort_unnamed_constructors_first
|
||||
# - super_goes_last # no longer needed w/ Dart 2
|
||||
- test_types_in_equals
|
||||
- throw_in_finally
|
||||
# - type_annotate_public_apis # subset of always_specify_types
|
||||
- type_init_formals
|
||||
# - unawaited_futures
|
||||
- unnecessary_brace_in_string_interps
|
||||
- unnecessary_getters_setters
|
||||
- unnecessary_statements
|
||||
- unrelated_type_equality_checks
|
||||
- valid_regexps
|
||||
public_member_api_docs: true
|
||||
prefer_final_in_for_each: true
|
||||
prefer_final_locals: true
|
||||
@@ -1,7 +0,0 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.example.example
|
||||
|
||||
import com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin
|
||||
import io.flutter.app.FlutterApplication
|
||||
import io.flutter.plugin.common.PluginRegistry
|
||||
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
|
||||
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
|
||||
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
|
||||
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
|
||||
import io.flutter.plugins.pathprovider.PathProviderPlugin
|
||||
|
||||
class Application : FlutterApplication(), PluginRegistrantCallback {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlutterFirebaseMessagingService.setPluginRegistrant(this)
|
||||
}
|
||||
|
||||
override fun registerWith(registry: PluginRegistry?) {
|
||||
PathProviderPlugin.registerWith(registry?.registrarFor(
|
||||
"io.flutter.plugins.pathprovider.PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.registerWith(registry?.registrarFor(
|
||||
"io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"))
|
||||
FlutterLocalNotificationsPlugin.registerWith(registry?.registrarFor(
|
||||
"com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin"))
|
||||
FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.example.example
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,15 +0,0 @@
|
||||
include ':app'
|
||||
|
||||
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||
|
||||
def plugins = new Properties()
|
||||
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||
if (pluginsFile.exists()) {
|
||||
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||
}
|
||||
|
||||
plugins.each { name, path ->
|
||||
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||
include ":$name"
|
||||
project(":$name").projectDir = pluginDirectory
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Notifications</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.usernotifications.service</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,182 +0,0 @@
|
||||
//
|
||||
// NotificationService.swift
|
||||
// Notifications
|
||||
//
|
||||
// Created by Salvatore Giordano on 25/03/2020.
|
||||
// Copyright © 2020 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
|
||||
import UserNotifications
|
||||
//import StreamChatClient
|
||||
|
||||
final class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||
var bestAttemptContent: UNMutableNotificationContent?
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
self.contentHandler = contentHandler
|
||||
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
|
||||
|
||||
guard let sharedDefaults = UserDefaults(suiteName: "group.io.stream.flutter"),
|
||||
let apiKey = sharedDefaults.string(forKey: "KEY_API_KEY"),
|
||||
let userId = sharedDefaults.string(forKey: "KEY_USER_ID"),
|
||||
let token = sharedDefaults.string(forKey: "KEY_TOKEN"),
|
||||
let messageId = bestAttemptContent?.userInfo["message_id"] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
// Client.config = .init(apiKey: apiKey, logOptions: .error)
|
||||
// Client.shared.set(user: User(id: userId), token: token) { res in
|
||||
// guard res.isConnected else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// Client.shared.message(withId: messageId) { [weak self] res in
|
||||
// if let message = res.value?.message,
|
||||
// let channel = res.value?.channel {
|
||||
// let messageWrapper = MessageWrapper(channel: channel, message: message)
|
||||
// if let encodedData = try? JSONEncoder.stream.encode(messageWrapper),
|
||||
// let encodedString = String(data: encodedData, encoding: .utf8) {
|
||||
// let storedMessages = sharedDefaults.stringArray(forKey: "messageQueue") ?? []
|
||||
// sharedDefaults.setValue(storedMessages + [encodedString], forKey: "messageQueue")
|
||||
//
|
||||
// // Modify the notification content here...
|
||||
// self?.bestAttemptContent?.title = "[modified] \(self?.bestAttemptContent?.title ?? "<NoContent>")"
|
||||
// contentHandler(self?.bestAttemptContent ?? request.content)
|
||||
// }
|
||||
// Client.shared.disconnect()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
override func serviceExtensionTimeWillExpire() {
|
||||
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public struct MessageWrapper: Encodable {
|
||||
// private enum CodingKeys: String, CodingKey {
|
||||
// case id
|
||||
// case channel
|
||||
// case type
|
||||
// case user
|
||||
// case created = "created_at"
|
||||
// case updated = "updated_at"
|
||||
// case text
|
||||
// case command
|
||||
// case args
|
||||
// case attachments
|
||||
// case parentId = "parent_id"
|
||||
// case showReplyInChannel = "show_in_channel"
|
||||
// case mentionedUsers = "mentioned_users"
|
||||
// }
|
||||
//
|
||||
// init(channel: Channel, message: Message) {
|
||||
// id = message.id
|
||||
// type = message.type
|
||||
// user = message.user
|
||||
// created = message.created
|
||||
// updated = message.updated
|
||||
// text = message.text
|
||||
// command = message.command
|
||||
// args = message.args
|
||||
// attachments = message.attachments
|
||||
// parentId = message.parentId
|
||||
// showReplyInChannel = message.showReplyInChannel
|
||||
// mentionedUsers = message.mentionedUsers
|
||||
// extraData = message.extraData
|
||||
// self.channel = ChannelWrapper(channel: channel)
|
||||
// }
|
||||
//
|
||||
// /// A message id.
|
||||
// public let id: String
|
||||
// /// The channel cid.
|
||||
// public let channel: ChannelWrapper?
|
||||
// /// A message type (see `MessageType`).
|
||||
// public let type: MessageType
|
||||
// /// A user (see `User`).
|
||||
// public let user: User
|
||||
// /// A created date.
|
||||
// public let created: Date
|
||||
// /// A updated date.
|
||||
// public let updated: Date
|
||||
// /// A text.
|
||||
// public let text: String
|
||||
// /// A used command name.
|
||||
// public let command: String?
|
||||
// /// A used command args.
|
||||
// public let args: String?
|
||||
// /// Attachments (see `Attachment`).
|
||||
// public let attachments: [Attachment]
|
||||
// /// A parent message id.
|
||||
// public let parentId: String?
|
||||
// /// Check if this reply message needs to show in the channel.
|
||||
// public let showReplyInChannel: Bool
|
||||
// /// Mentioned users (see `User`).
|
||||
// public let mentionedUsers: [User]
|
||||
// /// An extra data for the message.
|
||||
// public let extraData: Codable?
|
||||
//}
|
||||
//
|
||||
//public struct ChannelWrapper: Encodable {
|
||||
// /// Coding keys for the encoding.
|
||||
// private enum CodingKeys: String, CodingKey {
|
||||
// case id
|
||||
// case cid
|
||||
// case type
|
||||
// case name
|
||||
// case imageURL = "image"
|
||||
// case members
|
||||
// case lastMessageDate = "last_message_at"
|
||||
// case createdBy = "created_by"
|
||||
// case created = "created_at"
|
||||
// case deleted = "deleted_at"
|
||||
// case frozen
|
||||
// }
|
||||
//
|
||||
// init(channel: Channel) {
|
||||
// id = channel.id
|
||||
// cid = channel.cid
|
||||
// type = channel.type
|
||||
// name = channel.name
|
||||
// imageURL = channel.imageURL
|
||||
// lastMessageDate = channel.lastMessageDate
|
||||
// created = channel.created
|
||||
// deleted = channel.deleted
|
||||
// createdBy = channel.createdBy
|
||||
// config = channel.config
|
||||
// frozen = channel.frozen
|
||||
// extraData = channel.extraData
|
||||
// }
|
||||
//
|
||||
// /// A channel id.
|
||||
// public let id: String
|
||||
// /// A channel type + id.
|
||||
// public let cid: ChannelId
|
||||
// /// A channel type.
|
||||
// public let type: ChannelType
|
||||
// /// A channel name.
|
||||
// public let name: String?
|
||||
// /// An image of the channel.
|
||||
// public let imageURL: URL?
|
||||
// /// The last message date.
|
||||
// public let lastMessageDate: Date?
|
||||
// /// A channel created date.
|
||||
// public let created: Date
|
||||
// /// A channel deleted date.
|
||||
// public let deleted: Date?
|
||||
// /// A creator of the channel.
|
||||
// public let createdBy: User?
|
||||
// /// A config.
|
||||
// public let config: Channel.Config
|
||||
// /// Checks if the channel is frozen.
|
||||
// public let frozen: Bool
|
||||
// /// A list of user ids of the channel members.
|
||||
// public let members = Set<Member>()
|
||||
// /// An extra data for the channel.
|
||||
// public let extraData: Codable?
|
||||
//}
|
||||
@@ -1,43 +0,0 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
pod 'StreamChatClient'
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
@@ -1 +0,0 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
@@ -1,133 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Fifth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||
///
|
||||
/// Customizing how messages are rendered is another very common use-case that the SDK supports easily.
|
||||
///
|
||||
/// Replace the built-in message component with your own is done by passing it as a builder function to the [MessageListView] widget.
|
||||
///
|
||||
/// The message builder function will get the usual [BuildContext] argument as well as the [Message] object and its position inside the list.
|
||||
///
|
||||
/// If you look at the code you can see that we use [StreamChat.of] to retrieve the current user so that we can style messages own messages in a different way.
|
||||
///
|
||||
/// Since custom widgets and builders are always children of [StreamChat] or part of a [Channel],
|
||||
/// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly
|
||||
/// or to retrieve outer scope needed such as messages from the [Channel.state].
|
||||
void main() async {
|
||||
final client = Client(
|
||||
's2dxdhpxd94g',
|
||||
logLevel: Level.INFO,
|
||||
);
|
||||
|
||||
await client.setUser(
|
||||
User(id: 'super-band-9'),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
|
||||
runApp(MyApp(client));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final Client client;
|
||||
|
||||
MyApp(this.client);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
builder: (context, child) => StreamChat(
|
||||
child: child,
|
||||
client: client,
|
||||
),
|
||||
home: Container(
|
||||
child: ChannelListPage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelListPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
filter: {
|
||||
'members': {
|
||||
'\$in': [StreamChat.of(context).user.id],
|
||||
}
|
||||
},
|
||||
sort: [SortOption('last_message_at')],
|
||||
pagination: PaginationParams(
|
||||
limit: 20,
|
||||
),
|
||||
channelWidget: ChannelPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelPage extends StatelessWidget {
|
||||
const ChannelPage({
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: ChannelHeader(),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: MessageListView(
|
||||
messageBuilder: _messageBuilder,
|
||||
),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _messageBuilder(
|
||||
BuildContext context,
|
||||
MessageDetails details,
|
||||
List<Message> messages,
|
||||
) {
|
||||
final message = details.message;
|
||||
final color = details.isMyMessage ? Colors.blueGrey : Colors.blue;
|
||||
if (message.isSystem) {
|
||||
return SizedBox();
|
||||
}
|
||||
return MessageWidget(
|
||||
message: message,
|
||||
messageTheme: details.isMyMessage
|
||||
? StreamChatTheme.of(context).ownMessageTheme
|
||||
: StreamChatTheme.of(context).otherMessageTheme,
|
||||
borderSide: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
),
|
||||
padding: const EdgeInsets.all(2),
|
||||
attachmentBorderSide: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
),
|
||||
attachmentPadding: EdgeInsets.all(8),
|
||||
borderRadiusGeometry: BorderRadius.vertical(
|
||||
top: !details.isLastUser ? Radius.circular(16) : Radius.zero,
|
||||
bottom: !details.isNextUser ? Radius.circular(16) : Radius.zero,
|
||||
),
|
||||
showSendingIndicator: DisplayWidget.gone,
|
||||
reverse: false,
|
||||
showUserAvatar:
|
||||
details.isNextUser ? DisplayWidget.hide : DisplayWidget.show,
|
||||
showTimestamp: !details.isNextUser,
|
||||
showUsername: !details.isNextUser,
|
||||
showReactions: false,
|
||||
showReplyIndicator: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility that Flutter provides. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:example/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
|
||||
import '../lib/single_conversation.dart' as app;
|
||||
|
||||
void main() async {
|
||||
enableFlutterDriverExtension();
|
||||
|
||||
await app.main();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('Single conversation', () async {
|
||||
final inputFinder = find.byValueKey('messageInputText');
|
||||
final sendButtonFinder = find.byValueKey('sendButton');
|
||||
final messageListViewFinder = find.byValueKey('messageListView');
|
||||
|
||||
FlutterDriver driver = await FlutterDriver.connect();
|
||||
// Connect to the Flutter driver before running any tests.
|
||||
|
||||
sleep(Duration(seconds: 5));
|
||||
|
||||
await driver.waitFor(inputFinder);
|
||||
|
||||
await driver.tap(inputFinder);
|
||||
|
||||
sleep(Duration(seconds: 1));
|
||||
|
||||
await driver.enterText('hey');
|
||||
|
||||
sleep(Duration(seconds: 1));
|
||||
|
||||
await driver.tap(sendButtonFinder);
|
||||
|
||||
sleep(Duration(seconds: 1));
|
||||
|
||||
await driver.scroll(
|
||||
messageListViewFinder,
|
||||
0,
|
||||
2000,
|
||||
Duration(seconds: 1),
|
||||
);
|
||||
|
||||
sleep(Duration(seconds: 1));
|
||||
|
||||
// Close the connection to the driver after the tests have completed.
|
||||
sleep(Duration(seconds: 5));
|
||||
if (driver != null) {
|
||||
await driver.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Before Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="A new Flutter project.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="example">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>example</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('flutter_service_worker.js');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script defer src="sql-wasm.js"></script>
|
||||
<script src="main.dart.js" type="application/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "example",
|
||||
"short_name": "example",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "#0175C2",
|
||||
"theme_color": "#0175C2",
|
||||
"description": "A new Flutter project.",
|
||||
"orientation": "portrait-primary",
|
||||
"prefer_related_applications": false,
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/Icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "icons/Icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`,
|
||||
// which is able to be used/called before the WASM is loaded.
|
||||
// The modularization below exports a promise that loads and resolves to the actual sql.js module.
|
||||
// That way, this module can't be used before the WASM is finished loading.
|
||||
|
||||
// We are going to define a function that a user will call to start loading initializing our Sql.js library
|
||||
// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module
|
||||
// Instead, we want to return the previously loaded module
|
||||
|
||||
// TODO: Make this not declare a global if used in the browser
|
||||
var initSqlJsPromise = undefined;
|
||||
|
||||
var initSqlJs = function (moduleConfig) {
|
||||
|
||||
if (initSqlJsPromise){
|
||||
return initSqlJsPromise;
|
||||
}
|
||||
// If we're here, we've never called this function before
|
||||
initSqlJsPromise = new Promise((resolveModule, reject) => {
|
||||
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
|
||||
// The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add
|
||||
// properties to it, like `preRun`, `postRun`, etc
|
||||
// We are using that to get notified when the WASM has finished loading.
|
||||
// Only then will we return our promise
|
||||
|
||||
// If they passed in a moduleConfig object, use that
|
||||
// Otherwise, initialize Module to the empty object
|
||||
var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {};
|
||||
|
||||
// EMCC only allows for a single onAbort function (not an array of functions)
|
||||
// So if the user defined their own onAbort function, we remember it and call it
|
||||
var originalOnAbortFunction = Module['onAbort'];
|
||||
Module['onAbort'] = function (errorThatCausedAbort) {
|
||||
reject(new Error(errorThatCausedAbort));
|
||||
if (originalOnAbortFunction){
|
||||
originalOnAbortFunction(errorThatCausedAbort);
|
||||
}
|
||||
};
|
||||
|
||||
Module['postRun'] = Module['postRun'] || [];
|
||||
Module['postRun'].push(function () {
|
||||
// When Emscripted calls postRun, this promise resolves with the built Module
|
||||
resolveModule(Module);
|
||||
});
|
||||
|
||||
// There is a section of code in the emcc-generated code below that looks like this:
|
||||
// (Note that this is lowercase `module`)
|
||||
// if (typeof module !== 'undefined') {
|
||||
// module['exports'] = Module;
|
||||
// }
|
||||
// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js!
|
||||
// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags,
|
||||
// but that carries with it additional unnecessary baggage/bugs we don't want either.
|
||||
// So, we have three options:
|
||||
// 1) We undefine `module`
|
||||
// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later
|
||||
// 3) We write a script to remove those lines of code as part of the Make process.
|
||||
//
|
||||
// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward
|
||||
// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future.
|
||||
// That's a nice side effect since we're handling the modularization efforts ourselves
|
||||
module = undefined;
|
||||
|
||||
// The emcc-generated code and shell-post.js code goes below,
|
||||
// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort
|
||||
var aa;var f;f||(f=typeof Module !== 'undefined' ? Module : {});
|
||||
var va=function(){var a;var b=h(4);var c={};var d=function(){function a(a,b){this.fb=a;this.db=b;this.nb=1;this.Eb=[]}a.prototype.bind=function(a){if(!this.fb)throw"Statement closed";this.reset();return Array.isArray(a)?this.lc(a):this.mc(a)};a.prototype.step=function(){var a;if(!this.fb)throw"Statement closed";this.nb=1;switch(a=Tb(this.fb)){case c.hc:return!0;case c.DONE:return!1;default:return this.db.handleError(a)}};a.prototype.sc=function(a){null==a&&(a=this.nb++);return Ub(this.fb,a)};a.prototype.tc=
|
||||
function(a){null==a&&(a=this.nb++);return Vb(this.fb,a)};a.prototype.getBlob=function(a){var b;null==a&&(a=this.nb++);var c=Wb(this.fb,a);var d=Xb(this.fb,a);var e=new Uint8Array(c);for(a=b=0;0<=c?b<c:b>c;a=0<=c?++b:--b)e[a]=l[d+a];return e};a.prototype.get=function(a){var b,d;null!=a&&this.bind(a)&&this.step();var e=[];a=b=0;for(d=ib(this.fb);0<=d?b<d:b>d;a=0<=d?++b:--b)switch(Yb(this.fb,a)){case c.fc:case c.FLOAT:e.push(this.sc(a));break;case c.ic:e.push(this.tc(a));break;case c.Zb:e.push(this.getBlob(a));
|
||||
break;default:e.push(null)}return e};a.prototype.getColumnNames=function(){var a,b;var c=[];var d=a=0;for(b=ib(this.fb);0<=b?a<b:a>b;d=0<=b?++a:--a)c.push(Zb(this.fb,d));return c};a.prototype.getAsObject=function(a){var b,c;var d=this.get(a);var e=this.getColumnNames();var g={};a=b=0;for(c=e.length;b<c;a=++b){var Sb=e[a];g[Sb]=d[a]}return g};a.prototype.run=function(a){null!=a&&this.bind(a);this.step();return this.reset()};a.prototype.pc=function(a,b){var c;null==b&&(b=this.nb++);a=ba(a);this.Eb.push(c=
|
||||
ea(a));this.db.handleError(ca(this.fb,b,c,a.length-1,0))};a.prototype.kc=function(a,b){var c;null==b&&(b=this.nb++);this.Eb.push(c=ea(a));this.db.handleError(Ia(this.fb,b,c,a.length,0))};a.prototype.oc=function(a,b){null==b&&(b=this.nb++);this.db.handleError((a===(a|0)?$b:ac)(this.fb,b,a))};a.prototype.nc=function(a){null==a&&(a=this.nb++);Ia(this.fb,a,0,0,0)};a.prototype.Qb=function(a,b){null==b&&(b=this.nb++);switch(typeof a){case "string":this.pc(a,b);break;case "number":case "boolean":this.oc(a+
|
||||
0,b);break;case "object":if(null===a)this.nc(b);else if(null!=a.length)this.kc(a,b);else throw"Wrong API use : tried to bind a value of an unknown type ("+a+").";}};a.prototype.mc=function(a){var b;for(b in a){var c=a[b];var d=bc(this.fb,b);0!==d&&this.Qb(c,d)}return!0};a.prototype.lc=function(a){var b,c;var d=b=0;for(c=a.length;b<c;d=++b){var e=a[d];this.Qb(e,d+1)}return!0};a.prototype.reset=function(){this.freemem();return cc(this.fb)===c.xb&&dc(this.fb)===c.xb};a.prototype.freemem=function(){for(var a;a=
|
||||
this.Eb.pop();)ha(a);return null};a.prototype.free=function(){this.freemem();var a=ec(this.fb)===c.xb;delete this.db.Bb[this.fb];this.fb=da;return a};return a}();var e=function(){function a(a){this.filename="dbfile_"+(4294967295*Math.random()>>>0);if(null!=a){var c=this.filename,d=c?n("/",c):"/";c=ia(!0,!0);d=ja(d,(void 0!==c?c:438)&4095|32768,0);if(a){if("string"===typeof a){for(var e=Array(a.length),k=0,m=a.length;k<m;++k)e[k]=a.charCodeAt(k);a=e}ka(d,c|146);e=p(d,"w");la(e,a,0,a.length,0,void 0);
|
||||
ma(e);ka(d,c)}}this.handleError(g(this.filename,b));this.db=q(b,"i32");fc(this.db);this.Bb={}}a.prototype.run=function(a,c){if(!this.db)throw"Database closed";c?(a=this.prepare(a,c),a.step(),a.free()):this.handleError(m(this.db,a,0,0,b));return this};a.prototype.exec=function(a){if(!this.db)throw"Database closed";var c=na();var e=oa(a)+1;var g=h(e);r(a,l,g,e);a=g;e=h(4);for(g=[];q(a,"i8")!==da;){pa(b);pa(e);this.handleError(fa(this.db,a,-1,b,e));var k=q(b,"i32");a=q(e,"i32");if(k!==da){var m=new d(k,
|
||||
this);for(k=null;m.step();)null===k&&(k={columns:m.getColumnNames(),values:[]},g.push(k)),k.values.push(m.get());m.free()}}qa(c);return g};a.prototype.each=function(a,b,c,d){"function"===typeof b&&(d=c,c=b,b=void 0);for(a=this.prepare(a,b);a.step();)c(a.getAsObject());a.free();if("function"===typeof d)return d()};a.prototype.prepare=function(a,c){pa(b);this.handleError(z(this.db,a,-1,b,da));a=q(b,"i32");if(a===da)throw"Nothing to prepare";var e=new d(a,this);null!=c&&e.bind(c);return this.Bb[a]=e};
|
||||
a.prototype["export"]=function(){var a;var c=this.Bb;for(e in c){var d=c[e];d.free()}this.handleError(k(this.db));d=this.filename;var e=e={encoding:"binary"};e.flags=e.flags||"r";e.encoding=e.encoding||"binary";if("utf8"!==e.encoding&&"binary"!==e.encoding)throw Error('Invalid encoding type "'+e.encoding+'"');c=p(d,e.flags);d=ra(d).size;var m=new Uint8Array(d);sa(c,m,0,d,0);"utf8"===e.encoding?a=t(m,0):"binary"===e.encoding&&(a=m);ma(c);this.handleError(g(this.filename,b));this.db=q(b,"i32");return a};
|
||||
a.prototype.close=function(){var a;var b=this.Bb;for(a in b){var c=b[a];c.free()}this.handleError(k(this.db));ta("/"+this.filename);return this.db=null};a.prototype.handleError=function(a){if(a===c.xb)return null;a=hc(this.db);throw Error(a);};a.prototype.getRowsModified=function(){return y(this.db)};a.prototype.create_function=function(a,b){var d=ua(function(a,c,d){var e,g;var k=[];for(e=g=0;0<=c?g<c:g>c;e=0<=c?++g:--g){var m=q(d+4*e,"i32");var z=jc(m);e=function(){switch(!1){case 1!==z:return kc;
|
||||
case 2!==z:return lc;case 3!==z:return mc;case 4!==z:return function(a){var b,c;var d=nc(a);var e=oc(a);a=new Uint8Array(d);for(b=c=0;0<=d?c<d:c>d;b=0<=d?++c:--c)a[b]=l[e+b];return a};default:return function(){return null}}}();e=e(m);k.push(e)}if(c=b.apply(null,k))switch(typeof c){case "number":return pc(a,c);case "string":return qc(a,c,-1,-1)}else return rc(a)});this.handleError(sc(this.db,a,b.length,c.jc,0,d,0,0,0));return this};return a}();var g=f.cwrap("sqlite3_open","number",["string","number"]);
|
||||
var k=f.cwrap("sqlite3_close_v2","number",["number"]);var m=f.cwrap("sqlite3_exec","number",["number","string","number","number","number"]);f.cwrap("sqlite3_free","",["number"]);var y=f.cwrap("sqlite3_changes","number",["number"]);var z=f.cwrap("sqlite3_prepare_v2","number",["number","string","number","number","number"]);var fa=f.cwrap("sqlite3_prepare_v2","number",["number","number","number","number","number"]);var ca=f.cwrap("sqlite3_bind_text","number",["number","number","number","number","number"]);
|
||||
var Ia=f.cwrap("sqlite3_bind_blob","number",["number","number","number","number","number"]);var ac=f.cwrap("sqlite3_bind_double","number",["number","number","number"]);var $b=f.cwrap("sqlite3_bind_int","number",["number","number","number"]);var bc=f.cwrap("sqlite3_bind_parameter_index","number",["number","string"]);var Tb=f.cwrap("sqlite3_step","number",["number"]);var hc=f.cwrap("sqlite3_errmsg","string",["number"]);var ib=f.cwrap("sqlite3_data_count","number",["number"]);var Ub=f.cwrap("sqlite3_column_double",
|
||||
"number",["number","number"]);var Vb=f.cwrap("sqlite3_column_text","string",["number","number"]);var Xb=f.cwrap("sqlite3_column_blob","number",["number","number"]);var Wb=f.cwrap("sqlite3_column_bytes","number",["number","number"]);var Yb=f.cwrap("sqlite3_column_type","number",["number","number"]);var Zb=f.cwrap("sqlite3_column_name","string",["number","number"]);var dc=f.cwrap("sqlite3_reset","number",["number"]);var cc=f.cwrap("sqlite3_clear_bindings","number",["number"]);var ec=f.cwrap("sqlite3_finalize",
|
||||
"number",["number"]);var sc=f.cwrap("sqlite3_create_function_v2","number","number string number number number number number number number".split(" "));var jc=f.cwrap("sqlite3_value_type","number",["number"]);var nc=f.cwrap("sqlite3_value_bytes","number",["number"]);var mc=f.cwrap("sqlite3_value_text","string",["number"]);var kc=f.cwrap("sqlite3_value_int","number",["number"]);var oc=f.cwrap("sqlite3_value_blob","number",["number"]);var lc=f.cwrap("sqlite3_value_double","number",["number"]);var pc=
|
||||
f.cwrap("sqlite3_result_double","",["number","number"]);var rc=f.cwrap("sqlite3_result_null","",["number"]);var qc=f.cwrap("sqlite3_result_text","",["number","string","number","number"]);var fc=f.cwrap("RegisterExtensionFunctions","number",["number"]);this.SQL={Database:e};for(a in this.SQL)f[a]=this.SQL[a];var da=0;c.xb=0;c.we=1;c.Pe=2;c.Ze=3;c.Cc=4;c.Ec=5;c.Se=6;c.NOMEM=7;c.bf=8;c.Qe=9;c.Re=10;c.Hc=11;c.NOTFOUND=12;c.Oe=13;c.Fc=14;c.$e=15;c.EMPTY=16;c.cf=17;c.df=18;c.Gc=19;c.Te=20;c.Ue=21;c.Ve=
|
||||
22;c.Dc=23;c.Ne=24;c.af=25;c.We=26;c.Xe=27;c.ef=28;c.hc=100;c.DONE=101;c.fc=1;c.FLOAT=2;c.ic=3;c.Zb=4;c.Ye=5;c.jc=1}.bind(this);f.preRun=f.preRun||[];f.preRun.push(va);var wa={},u;for(u in f)f.hasOwnProperty(u)&&(wa[u]=f[u]);f.arguments=[];f.thisProgram="./this.program";f.quit=function(a,b){throw b;};f.preRun=[];f.postRun=[];var v=!1,w=!1,x=!1,xa=!1;v="object"===typeof window;w="function"===typeof importScripts;x="object"===typeof process&&"function"===typeof require&&!v&&!w;xa=!v&&!x&&!w;var A="";
|
||||
if(x){A=__dirname+"/";var ya,za;f.read=function(a,b){ya||(ya=require("fs"));za||(za=require("path"));a=za.normalize(a);a=ya.readFileSync(a);return b?a:a.toString()};f.readBinary=function(a){a=f.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};1<process.argv.length&&(f.thisProgram=process.argv[1].replace(/\\/g,"/"));f.arguments=process.argv.slice(2);"undefined"!==typeof module&&(module.exports=f);process.on("unhandledRejection",B);f.quit=function(a){process.exit(a)};f.inspect=
|
||||
function(){return"[Emscripten Module object]"}}else if(xa)"undefined"!=typeof read&&(f.read=function(a){return read(a)}),f.readBinary=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");assert("object"===typeof a);return a},"undefined"!=typeof scriptArgs?f.arguments=scriptArgs:"undefined"!=typeof arguments&&(f.arguments=arguments),"function"===typeof quit&&(f.quit=function(a){quit(a)});else if(v||w)w?A=self.location.href:document.currentScript&&(A=
|
||||
document.currentScript.src),A=0!==A.indexOf("blob:")?A.substr(0,A.lastIndexOf("/")+1):"",f.read=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},w&&(f.readBinary=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),f.readAsync=function(a,b,c){var d=new XMLHttpRequest;d.open("GET",a,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):
|
||||
c()};d.onerror=c;d.send(null)},f.setWindowTitle=function(a){document.title=a};var Aa=f.print||("undefined"!==typeof console?console.log.bind(console):"undefined"!==typeof print?print:null),C=f.printErr||("undefined"!==typeof printErr?printErr:"undefined"!==typeof console&&console.warn.bind(console)||Aa);for(u in wa)wa.hasOwnProperty(u)&&(f[u]=wa[u]);wa=void 0;function Ba(a){var b=D[Ca>>2];a=b+a+15&-16;if(a<=Da())D[Ca>>2]=a;else if(!Ea(a))return 0;return b}
|
||||
var Fa={"f64-rem":function(a,b){return a%b},"debugger":function(){debugger}},Ga=1,E=Array(64);function ua(a){for(var b=0;64>b;b++)if(!E[b])return E[b]=a,Ga+b;throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.";}"object"!==typeof WebAssembly&&C("no native wasm support detected");
|
||||
function q(a,b){b=b||"i8";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return l[a>>0];case "i8":return l[a>>0];case "i16":return Ha[a>>1];case "i32":return D[a>>2];case "i64":return D[a>>2];case "float":return Ja[a>>2];case "double":return Ka[a>>3];default:B("invalid type for getValue: "+b)}return null}var La,Ma=!1;function assert(a,b){a||B("Assertion failed: "+b)}function Na(a){var b=f["_"+a];assert(b,"Cannot call unknown function "+a+", make sure it is exported");return b}
|
||||
function Oa(a,b,c,d){var e={string:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var c=(a.length<<2)+1;b=h(c);r(a,F,b,c)}return b},array:function(a){var b=h(a.length);l.set(a,b);return b}},g=Na(a),k=[];a=0;if(d)for(var m=0;m<d.length;m++){var y=e[c[m]];y?(0===a&&(a=na()),k[m]=y(d[m])):k[m]=d[m]}c=g.apply(null,k);c=function(a){return"string"===b?G(a):"boolean"===b?!!a:a}(c);0!==a&&qa(a);return c}
|
||||
function pa(a){var b="i32";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":l[a>>0]=0;break;case "i8":l[a>>0]=0;break;case "i16":Ha[a>>1]=0;break;case "i32":D[a>>2]=0;break;case "i64":aa=[0,1<=+Pa(0)?~~+Qa(0)>>>0:0];D[a>>2]=aa[0];D[a+4>>2]=aa[1];break;case "float":Ja[a>>2]=0;break;case "double":Ka[a>>3]=0;break;default:B("invalid type for setValue: "+b)}}var Ra=0,Sa=3;
|
||||
function ea(a){var b=Ra;if("number"===typeof a){var c=!0;var d=a}else c=!1,d=a.length;b=b==Sa?e:[Ta,h,Ba][b](Math.max(d,1));if(c){var e=b;assert(0==(b&3));for(a=b+(d&-4);e<a;e+=4)D[e>>2]=0;for(a=b+d;e<a;)l[e++>>0]=0;return b}a.subarray||a.slice?F.set(a,b):F.set(new Uint8Array(a),b);return b}var Ua="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function t(a,b,c){var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16<c-b&&a.subarray&&Ua)return Ua.decode(a.subarray(b,c));for(d="";b<c;){var e=a[b++];if(e&128){var g=a[b++]&63;if(192==(e&224))d+=String.fromCharCode((e&31)<<6|g);else{var k=a[b++]&63;e=224==(e&240)?(e&15)<<12|g<<6|k:(e&7)<<18|g<<12|k<<6|a[b++]&63;65536>e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d}function G(a){return a?t(F,a,void 0):""}
|
||||
function r(a,b,c,d){if(!(0<d))return 0;var e=c;d=c+d-1;for(var g=0;g<a.length;++g){var k=a.charCodeAt(g);if(55296<=k&&57343>=k){var m=a.charCodeAt(++g);k=65536+((k&1023)<<10)|m&1023}if(127>=k){if(c>=d)break;b[c++]=k}else{if(2047>=k){if(c+1>=d)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=d)break;b[c++]=224|k>>12}else{if(c+3>=d)break;b[c++]=240|k>>18;b[c++]=128|k>>12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-e}
|
||||
function oa(a){for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}return b}"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");function Va(a){return a.replace(/__Z[\w\d_]+/g,function(a){return a===a?a:a+" ["+a+"]"})}function Wa(a){0<a%65536&&(a+=65536-a%65536);return a}var buffer,l,F,Ha,D,Ja,Ka;
|
||||
function Xa(){f.HEAP8=l=new Int8Array(buffer);f.HEAP16=Ha=new Int16Array(buffer);f.HEAP32=D=new Int32Array(buffer);f.HEAPU8=F=new Uint8Array(buffer);f.HEAPU16=new Uint16Array(buffer);f.HEAPU32=new Uint32Array(buffer);f.HEAPF32=Ja=new Float32Array(buffer);f.HEAPF64=Ka=new Float64Array(buffer)}var Ca=60128,Ya=f.TOTAL_MEMORY||16777216;5242880>Ya&&C("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+Ya+"! (TOTAL_STACK=5242880)");
|
||||
f.buffer?buffer=f.buffer:"object"===typeof WebAssembly&&"function"===typeof WebAssembly.Memory?(La=new WebAssembly.Memory({initial:Ya/65536}),buffer=La.buffer):buffer=new ArrayBuffer(Ya);Xa();D[Ca>>2]=5303264;function Za(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b();else{var c=b.rc;"number"===typeof c?void 0===b.Fb?f.dynCall_v(c):f.dynCall_vi(c,b.Fb):c(void 0===b.Fb?null:b.Fb)}}}var $a=[],ab=[],bb=[],cb=[],db=!1;function eb(){var a=f.preRun.shift();$a.unshift(a)}
|
||||
var Pa=Math.abs,Qa=Math.ceil,H=0,fb=null,gb=null;f.preloadedImages={};f.preloadedAudios={};function hb(){var a=I;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var I="sql-wasm.wasm";if(!hb()){var jb=I;I=f.locateFile?f.locateFile(jb,A):A+jb}
|
||||
function kb(){try{if(f.wasmBinary)return new Uint8Array(f.wasmBinary);if(f.readBinary)return f.readBinary(I);throw"both async and sync fetching of the wasm failed";}catch(a){B(a)}}function lb(){return f.wasmBinary||!v&&!w||"function"!==typeof fetch?new Promise(function(a){a(kb())}):fetch(I,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+I+"'";return a.arrayBuffer()}).catch(function(){return kb()})}
|
||||
function mb(a){function b(a){f.asm=a.exports;H--;f.monitorRunDependencies&&f.monitorRunDependencies(H);0==H&&(null!==fb&&(clearInterval(fb),fb=null),gb&&(a=gb,gb=null,a()))}function c(a){b(a.instance)}function d(a){lb().then(function(a){return WebAssembly.instantiate(a,e)}).then(a,function(a){C("failed to asynchronously prepare wasm: "+a);B(a)})}var e={env:a,global:{NaN:NaN,Infinity:Infinity},"global.Math":Math,asm2wasm:Fa};H++;f.monitorRunDependencies&&f.monitorRunDependencies(H);if(f.instantiateWasm)try{return f.instantiateWasm(e,
|
||||
b)}catch(g){return C("Module.instantiateWasm callback failed with error: "+g),!1}f.wasmBinary||"function"!==typeof WebAssembly.instantiateStreaming||hb()||"function"!==typeof fetch?d(c):WebAssembly.instantiateStreaming(fetch(I,{credentials:"same-origin"}),e).then(c,function(a){C("wasm streaming compile failed: "+a);C("falling back to ArrayBuffer instantiation");d(c)});return{}}
|
||||
f.asm=function(a,b){b.memory=La;b.table=new WebAssembly.Table({initial:2560,maximum:2560,element:"anyfunc"});b.__memory_base=1024;b.__table_base=0;return mb(b)};ab.push({rc:function(){nb()}});var J={};
|
||||
function ob(a){if(ob.rb){var b=D[a>>2];var c=D[b>>2]}else ob.rb=!0,J.USER=J.LOGNAME="web_user",J.PATH="/",J.PWD="/",J.HOME="/home/web_user",J.LANG="C.UTF-8",J._=f.thisProgram,c=db?Ta(1024):Ba(1024),b=db?Ta(256):Ba(256),D[b>>2]=c,D[a>>2]=b;a=[];var d=0,e;for(e in J)if("string"===typeof J[e]){var g=e+"="+J[e];a.push(g);d+=g.length}if(1024<d)throw Error("Environment size exceeded TOTAL_ENV_SIZE!");for(e=0;e<a.length;e++){d=g=a[e];for(var k=c,m=0;m<d.length;++m)l[k++>>0]=d.charCodeAt(m);l[k>>0]=0;D[b+
|
||||
4*e>>2]=c;c+=g.length+1}D[b+4*a.length>>2]=0}function pb(a){f.___errno_location&&(D[f.___errno_location()>>2]=a);return a}function qb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a}function rb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=qb(a.split("/").filter(function(a){return!!a}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a}
|
||||
function sb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function tb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function ub(){var a=Array.prototype.slice.call(arguments,0);return rb(a.join("/"))}function n(a,b){return rb(a+"/"+b)}
|
||||
function vb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=qb(a.split("/").filter(function(a){return!!a}),!b).join("/");return(b?"/":"")+a||"."}var wb=[];function xb(a,b){wb[a]={input:[],output:[],ub:b};yb(a,zb)}
|
||||
var zb={open:function(a){var b=wb[a.node.rdev];if(!b)throw new K(L.Cb);a.tty=b;a.seekable=!1},close:function(a){a.tty.ub.flush(a.tty)},flush:function(a){a.tty.ub.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.ub.Xb)throw new K(L.Ob);for(var e=0,g=0;g<d;g++){try{var k=a.tty.ub.Xb(a.tty)}catch(m){throw new K(L.Lb);}if(void 0===k&&0===e)throw new K(L.ac);if(null===k||void 0===k)break;e++;b[c+g]=k}e&&(a.node.timestamp=Date.now());return e},write:function(a,b,c,d){if(!a.tty||!a.tty.ub.Ib)throw new K(L.Ob);
|
||||
try{for(var e=0;e<d;e++)a.tty.ub.Ib(a.tty,b[c+e])}catch(g){throw new K(L.Lb);}d&&(a.node.timestamp=Date.now());return e}},Ab={Xb:function(a){if(!a.input.length){var b=null;if(x){var c=new Buffer(256),d=0,e=process.stdin.fd;if("win32"!=process.platform){var g=!1;try{e=fs.openSync("/dev/stdin","r"),g=!0}catch(k){}}try{d=fs.readSync(e,c,0,256,null)}catch(k){if(-1!=k.toString().indexOf("EOF"))d=0;else throw k;}g&&fs.closeSync(e);0<d?b=c.slice(0,d).toString("utf-8"):b=null}else"undefined"!=typeof window&&
|
||||
"function"==typeof window.prompt?(b=window.prompt("Input: "),null!==b&&(b+="\n")):"function"==typeof readline&&(b=readline(),null!==b&&(b+="\n"));if(!b)return null;a.input=ba(b,!0)}return a.input.shift()},Ib:function(a,b){null===b||10===b?(Aa(t(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},flush:function(a){a.output&&0<a.output.length&&(Aa(t(a.output,0)),a.output=[])}},Bb={Ib:function(a,b){null===b||10===b?(C(t(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},flush:function(a){a.output&&0<a.output.length&&
|
||||
(C(t(a.output,0)),a.output=[])}},M={mb:null,jb:function(){return M.createNode(null,"/",16895,0)},createNode:function(a,b,c,d){if(24576===(c&61440)||4096===(c&61440))throw new K(L.dc);M.mb||(M.mb={dir:{node:{lb:M.ab.lb,hb:M.ab.hb,lookup:M.ab.lookup,vb:M.ab.vb,rename:M.ab.rename,unlink:M.ab.unlink,rmdir:M.ab.rmdir,readdir:M.ab.readdir,symlink:M.ab.symlink},stream:{ob:M.cb.ob}},file:{node:{lb:M.ab.lb,hb:M.ab.hb},stream:{ob:M.cb.ob,read:M.cb.read,write:M.cb.write,Pb:M.cb.Pb,zb:M.cb.zb,Ab:M.cb.Ab}},link:{node:{lb:M.ab.lb,
|
||||
hb:M.ab.hb,readlink:M.ab.readlink},stream:{}},Sb:{node:{lb:M.ab.lb,hb:M.ab.hb},stream:Cb}});c=Db(a,b,c,d);N(c.mode)?(c.ab=M.mb.dir.node,c.cb=M.mb.dir.stream,c.bb={}):32768===(c.mode&61440)?(c.ab=M.mb.file.node,c.cb=M.mb.file.stream,c.gb=0,c.bb=null):40960===(c.mode&61440)?(c.ab=M.mb.link.node,c.cb=M.mb.link.stream):8192===(c.mode&61440)&&(c.ab=M.mb.Sb.node,c.cb=M.mb.Sb.stream);c.timestamp=Date.now();a&&(a.bb[b]=c);return c},ff:function(a){if(a.bb&&a.bb.subarray){for(var b=[],c=0;c<a.gb;++c)b.push(a.bb[c]);
|
||||
return b}return a.bb},gf:function(a){return a.bb?a.bb.subarray?a.bb.subarray(0,a.gb):new Uint8Array(a.bb):new Uint8Array},Tb:function(a,b){var c=a.bb?a.bb.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.bb,a.bb=new Uint8Array(b),0<a.gb&&a.bb.set(c.subarray(0,a.gb),0))},yc:function(a,b){if(a.gb!=b)if(0==b)a.bb=null,a.gb=0;else{if(!a.bb||a.bb.subarray){var c=a.bb;a.bb=new Uint8Array(new ArrayBuffer(b));c&&a.bb.set(c.subarray(0,Math.min(b,a.gb)))}else if(a.bb||(a.bb=
|
||||
[]),a.bb.length>b)a.bb.length=b;else for(;a.bb.length<b;)a.bb.push(0);a.gb=b}},ab:{lb:function(a){var b={};b.dev=8192===(a.mode&61440)?a.id:1;b.ino=a.id;b.mode=a.mode;b.nlink=1;b.uid=0;b.gid=0;b.rdev=a.rdev;N(a.mode)?b.size=4096:32768===(a.mode&61440)?b.size=a.gb:40960===(a.mode&61440)?b.size=a.link.length:b.size=0;b.atime=new Date(a.timestamp);b.mtime=new Date(a.timestamp);b.ctime=new Date(a.timestamp);b.pb=4096;b.blocks=Math.ceil(b.size/b.pb);return b},hb:function(a,b){void 0!==b.mode&&(a.mode=
|
||||
b.mode);void 0!==b.timestamp&&(a.timestamp=b.timestamp);void 0!==b.size&&M.yc(a,b.size)},lookup:function(){throw Eb[L.bc];},vb:function(a,b,c,d){return M.createNode(a,b,c,d)},rename:function(a,b,c){if(N(a.mode)){try{var d=O(b,c)}catch(g){}if(d)for(var e in d.bb)throw new K(L.Nb);}delete a.parent.bb[a.name];a.name=c;b.bb[c]=a;a.parent=b},unlink:function(a,b){delete a.bb[b]},rmdir:function(a,b){var c=O(a,b),d;for(d in c.bb)throw new K(L.Nb);delete a.bb[b]},readdir:function(a){var b=[".",".."],c;for(c in a.bb)a.bb.hasOwnProperty(c)&&
|
||||
b.push(c);return b},symlink:function(a,b,c){a=M.createNode(a,b,41471,0);a.link=c;return a},readlink:function(a){if(40960!==(a.mode&61440))throw new K(L.ib);return a.link}},cb:{read:function(a,b,c,d,e){var g=a.node.bb;if(e>=a.node.gb)return 0;a=Math.min(a.node.gb-e,d);if(8<a&&g.subarray)b.set(g.subarray(e,e+a),c);else for(d=0;d<a;d++)b[c+d]=g[e+d];return a},write:function(a,b,c,d,e,g){g=!1;if(!d)return 0;a=a.node;a.timestamp=Date.now();if(b.subarray&&(!a.bb||a.bb.subarray)){if(g)return a.bb=b.subarray(c,
|
||||
c+d),a.gb=d;if(0===a.gb&&0===e)return a.bb=new Uint8Array(b.subarray(c,c+d)),a.gb=d;if(e+d<=a.gb)return a.bb.set(b.subarray(c,c+d),e),d}M.Tb(a,e+d);if(a.bb.subarray&&b.subarray)a.bb.set(b.subarray(c,c+d),e);else for(g=0;g<d;g++)a.bb[e+g]=b[c+g];a.gb=Math.max(a.gb,e+d);return d},ob:function(a,b,c){1===c?b+=a.position:2===c&&32768===(a.node.mode&61440)&&(b+=a.node.gb);if(0>b)throw new K(L.ib);return b},Pb:function(a,b,c){M.Tb(a.node,b+c);a.node.gb=Math.max(a.node.gb,b+c)},zb:function(a,b,c,d,e,g,k){if(32768!==
|
||||
(a.node.mode&61440))throw new K(L.Cb);c=a.node.bb;if(k&2||c.buffer!==b&&c.buffer!==b.buffer){if(0<e||e+d<a.node.gb)c.subarray?c=c.subarray(e,e+d):c=Array.prototype.slice.call(c,e,e+d);a=!0;d=Ta(d);if(!d)throw new K(L.Mb);b.set(c,d)}else a=!1,d=c.byteOffset;return{xc:d,Db:a}},Ab:function(a,b,c,d,e){if(32768!==(a.node.mode&61440))throw new K(L.Cb);if(e&2)return 0;M.cb.write(a,b,0,d,c,!1);return 0}}},P={yb:!1,Ac:function(){P.yb=!!process.platform.match(/^win/);var a=process.binding("constants");a.fs&&
|
||||
(a=a.fs);P.Ub={1024:a.O_APPEND,64:a.O_CREAT,128:a.O_EXCL,0:a.O_RDONLY,2:a.O_RDWR,4096:a.O_SYNC,512:a.O_TRUNC,1:a.O_WRONLY}},Rb:function(a){return Buffer.rb?Buffer.from(a):new Buffer(a)},jb:function(a){assert(x);return P.createNode(null,"/",P.Wb(a.Hb.root),0)},createNode:function(a,b,c){if(!N(c)&&32768!==(c&61440)&&40960!==(c&61440))throw new K(L.ib);a=Db(a,b,c);a.ab=P.ab;a.cb=P.cb;return a},Wb:function(a){try{var b=fs.lstatSync(a);P.yb&&(b.mode=b.mode|(b.mode&292)>>2)}catch(c){if(!c.code)throw c;
|
||||
throw new K(L[c.code]);}return b.mode},kb:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.jb.Hb.root);b.reverse();return ub.apply(null,b)},qc:function(a){a&=-2656257;var b=0,c;for(c in P.Ub)a&c&&(b|=P.Ub[c],a^=c);if(a)throw new K(L.ib);return b},ab:{lb:function(a){a=P.kb(a);try{var b=fs.lstatSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}P.yb&&!b.pb&&(b.pb=4096);P.yb&&!b.blocks&&(b.blocks=(b.size+b.pb-1)/b.pb|0);return{dev:b.dev,ino:b.ino,mode:b.mode,nlink:b.nlink,
|
||||
uid:b.uid,gid:b.gid,rdev:b.rdev,size:b.size,atime:b.atime,mtime:b.mtime,ctime:b.ctime,pb:b.pb,blocks:b.blocks}},hb:function(a,b){var c=P.kb(a);try{void 0!==b.mode&&(fs.chmodSync(c,b.mode),a.mode=b.mode),void 0!==b.size&&fs.truncateSync(c,b.size)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},lookup:function(a,b){var c=n(P.kb(a),b);c=P.Wb(c);return P.createNode(a,b,c)},vb:function(a,b,c,d){a=P.createNode(a,b,c,d);b=P.kb(a);try{N(a.mode)?fs.mkdirSync(b,a.mode):fs.writeFileSync(b,"",{mode:a.mode})}catch(e){if(!e.code)throw e;
|
||||
throw new K(L[e.code]);}return a},rename:function(a,b,c){a=P.kb(a);b=n(P.kb(b),c);try{fs.renameSync(a,b)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},unlink:function(a,b){a=n(P.kb(a),b);try{fs.unlinkSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},rmdir:function(a,b){a=n(P.kb(a),b);try{fs.rmdirSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},readdir:function(a){a=P.kb(a);try{return fs.readdirSync(a)}catch(b){if(!b.code)throw b;throw new K(L[b.code]);}},symlink:function(a,
|
||||
b,c){a=n(P.kb(a),b);try{fs.symlinkSync(c,a)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},readlink:function(a){var b=P.kb(a);try{return b=fs.readlinkSync(b),b=Fb.relative(Fb.resolve(a.jb.Hb.root),b)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}}},cb:{open:function(a){var b=P.kb(a.node);try{32768===(a.node.mode&61440)&&(a.wb=fs.openSync(b,P.qc(a.flags)))}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},close:function(a){try{32768===(a.node.mode&61440)&&a.wb&&fs.closeSync(a.wb)}catch(b){if(!b.code)throw b;
|
||||
throw new K(L[b.code]);}},read:function(a,b,c,d,e){if(0===d)return 0;try{return fs.readSync(a.wb,P.Rb(b.buffer),c,d,e)}catch(g){throw new K(L[g.code]);}},write:function(a,b,c,d,e){try{return fs.writeSync(a.wb,P.Rb(b.buffer),c,d,e)}catch(g){throw new K(L[g.code]);}},ob:function(a,b,c){if(1===c)b+=a.position;else if(2===c&&32768===(a.node.mode&61440))try{b+=fs.fstatSync(a.wb).size}catch(d){throw new K(L[d.code]);}if(0>b)throw new K(L.ib);return b}}},Gb=null,Hb={},Q=[],Ib=1,R=null,Jb=!0,S={},K=null,
|
||||
Eb={};function T(a,b){a=vb("/",a);b=b||{};if(!a)return{path:"",node:null};var c={Vb:!0,Jb:0},d;for(d in c)void 0===b[d]&&(b[d]=c[d]);if(8<b.Jb)throw new K(40);a=qb(a.split("/").filter(function(a){return!!a}),!1);var e=Gb;c="/";for(d=0;d<a.length;d++){var g=d===a.length-1;if(g&&b.parent)break;e=O(e,a[d]);c=n(c,a[d]);e.sb&&(!g||g&&b.Vb)&&(e=e.sb.root);if(!g||b.qb)for(g=0;40960===(e.mode&61440);)if(e=Kb(c),c=vb(sb(c),e),e=T(c,{Jb:b.Jb}).node,40<g++)throw new K(40);}return{path:c,node:e}}
|
||||
function Lb(a){for(var b;;){if(a===a.parent)return a=a.jb.Yb,b?"/"!==a[a.length-1]?a+"/"+b:a+b:a;b=b?a.name+"/"+b:a.name;a=a.parent}}function Mb(a,b){for(var c=0,d=0;d<b.length;d++)c=(c<<5)-c+b.charCodeAt(d)|0;return(a+c>>>0)%R.length}function Nb(a){var b=Mb(a.parent.id,a.name);a.tb=R[b];R[b]=a}function Ob(a){var b=Mb(a.parent.id,a.name);if(R[b]===a)R[b]=a.tb;else for(b=R[b];b;){if(b.tb===a){b.tb=a.tb;break}b=b.tb}}
|
||||
function O(a,b){var c;if(c=(c=Pb(a,"x"))?c:a.ab.lookup?0:13)throw new K(c,a);for(c=R[Mb(a.id,b)];c;c=c.tb){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.ab.lookup(a,b)}
|
||||
function Db(a,b,c,d){Qb||(Qb=function(a,b,c,d){a||(a=this);this.parent=a;this.jb=a.jb;this.sb=null;this.id=Ib++;this.name=b;this.mode=c;this.ab={};this.cb={};this.rdev=d},Qb.prototype={},Object.defineProperties(Qb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}}}));a=new Qb(a,b,c,d);Nb(a);return a}
|
||||
function N(a){return 16384===(a&61440)}var Rb={r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218};function ic(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}function Pb(a,b){if(Jb)return 0;if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return 13}else return 13;return 0}function tc(a,b){try{return O(a,b),17}catch(c){}return Pb(a,"wx")}
|
||||
function uc(a,b,c){try{var d=O(a,b)}catch(e){return e.eb}if(a=Pb(a,"wx"))return a;if(c){if(!N(d.mode))return 20;if(d===d.parent||"/"===Lb(d))return 16}else if(N(d.mode))return 21;return 0}function vc(a){var b=4096;for(a=a||0;a<=b;a++)if(!Q[a])return a;throw new K(24);}
|
||||
function wc(a,b){xc||(xc=function(){},xc.prototype={},Object.defineProperties(xc.prototype,{object:{get:function(){return this.node},set:function(a){this.node=a}}}));var c=new xc,d;for(d in a)c[d]=a[d];a=c;b=vc(b);a.fd=b;return Q[b]=a}var Cb={open:function(a){a.cb=Hb[a.node.rdev].cb;a.cb.open&&a.cb.open(a)},ob:function(){throw new K(29);}};function yb(a,b){Hb[a]={cb:b}}
|
||||
function yc(a,b){var c="/"===b,d=!b;if(c&&Gb)throw new K(16);if(!c&&!d){var e=T(b,{Vb:!1});b=e.path;e=e.node;if(e.sb)throw new K(16);if(!N(e.mode))throw new K(20);}b={type:a,Hb:{},Yb:b,wc:[]};a=a.jb(b);a.jb=b;b.root=a;c?Gb=a:e&&(e.sb=b,e.jb&&e.jb.wc.push(b))}function ja(a,b,c){var d=T(a,{parent:!0}).node;a=tb(a);if(!a||"."===a||".."===a)throw new K(22);var e=tc(d,a);if(e)throw new K(e);if(!d.ab.vb)throw new K(1);return d.ab.vb(d,a,b,c)}function U(a,b){ja(a,(void 0!==b?b:511)&1023|16384,0)}
|
||||
function zc(a,b,c){"undefined"===typeof c&&(c=b,b=438);ja(a,b|8192,c)}function Ac(a,b){if(!vb(a))throw new K(2);var c=T(b,{parent:!0}).node;if(!c)throw new K(2);b=tb(b);var d=tc(c,b);if(d)throw new K(d);if(!c.ab.symlink)throw new K(1);c.ab.symlink(c,b,a)}
|
||||
function ta(a){var b=T(a,{parent:!0}).node,c=tb(a),d=O(b,c),e=uc(b,c,!1);if(e)throw new K(e);if(!b.ab.unlink)throw new K(1);if(d.sb)throw new K(16);try{S.willDeletePath&&S.willDeletePath(a)}catch(g){console.log("FS.trackingDelegate['willDeletePath']('"+a+"') threw an exception: "+g.message)}b.ab.unlink(b,c);Ob(d);try{if(S.onDeletePath)S.onDeletePath(a)}catch(g){console.log("FS.trackingDelegate['onDeletePath']('"+a+"') threw an exception: "+g.message)}}
|
||||
function Kb(a){a=T(a).node;if(!a)throw new K(2);if(!a.ab.readlink)throw new K(22);return vb(Lb(a.parent),a.ab.readlink(a))}function ra(a,b){a=T(a,{qb:!b}).node;if(!a)throw new K(2);if(!a.ab.lb)throw new K(1);return a.ab.lb(a)}function Bc(a){return ra(a,!0)}function ka(a,b){var c;"string"===typeof a?c=T(a,{qb:!0}).node:c=a;if(!c.ab.hb)throw new K(1);c.ab.hb(c,{mode:b&4095|c.mode&-4096,timestamp:Date.now()})}
|
||||
function Cc(a){var b;"string"===typeof a?b=T(a,{qb:!0}).node:b=a;if(!b.ab.hb)throw new K(1);b.ab.hb(b,{timestamp:Date.now()})}function Dc(a,b){if(0>b)throw new K(22);var c;"string"===typeof a?c=T(a,{qb:!0}).node:c=a;if(!c.ab.hb)throw new K(1);if(N(c.mode))throw new K(21);if(32768!==(c.mode&61440))throw new K(22);if(a=Pb(c,"w"))throw new K(a);c.ab.hb(c,{size:b,timestamp:Date.now()})}
|
||||
function p(a,b,c,d){if(""===a)throw new K(2);if("string"===typeof b){var e=Rb[b];if("undefined"===typeof e)throw Error("Unknown file open mode: "+b);b=e}c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;if("object"===typeof a)var g=a;else{a=rb(a);try{g=T(a,{qb:!(b&131072)}).node}catch(k){}}e=!1;if(b&64)if(g){if(b&128)throw new K(17);}else g=ja(a,c,0),e=!0;if(!g)throw new K(2);8192===(g.mode&61440)&&(b&=-513);if(b&65536&&!N(g.mode))throw new K(20);if(!e&&(c=g?40960===(g.mode&61440)?40:N(g.mode)&&
|
||||
("r"!==ic(b)||b&512)?21:Pb(g,ic(b)):2))throw new K(c);b&512&&Dc(g,0);b&=-641;d=wc({node:g,path:Lb(g),flags:b,seekable:!0,position:0,cb:g.cb,Bc:[],error:!1},d);d.cb.open&&d.cb.open(d);!f.logReadFiles||b&1||(Ec||(Ec={}),a in Ec||(Ec[a]=1,console.log("FS.trackingDelegate error on read file: "+a)));try{S.onOpenFile&&(g=0,1!==(b&2097155)&&(g|=1),0!==(b&2097155)&&(g|=2),S.onOpenFile(a,g))}catch(k){console.log("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+k.message)}return d}
|
||||
function ma(a){if(null===a.fd)throw new K(9);a.Gb&&(a.Gb=null);try{a.cb.close&&a.cb.close(a)}catch(b){throw b;}finally{Q[a.fd]=null}a.fd=null}function Fc(a,b,c){if(null===a.fd)throw new K(9);if(!a.seekable||!a.cb.ob)throw new K(29);if(0!=c&&1!=c&&2!=c)throw new K(22);a.position=a.cb.ob(a,b,c);a.Bc=[]}
|
||||
function sa(a,b,c,d,e){if(0>d||0>e)throw new K(22);if(null===a.fd)throw new K(9);if(1===(a.flags&2097155))throw new K(9);if(N(a.node.mode))throw new K(21);if(!a.cb.read)throw new K(22);var g="undefined"!==typeof e;if(!g)e=a.position;else if(!a.seekable)throw new K(29);b=a.cb.read(a,b,c,d,e);g||(a.position+=b);return b}
|
||||
function la(a,b,c,d,e,g){if(0>d||0>e)throw new K(22);if(null===a.fd)throw new K(9);if(0===(a.flags&2097155))throw new K(9);if(N(a.node.mode))throw new K(21);if(!a.cb.write)throw new K(22);a.flags&1024&&Fc(a,0,2);var k="undefined"!==typeof e;if(!k)e=a.position;else if(!a.seekable)throw new K(29);b=a.cb.write(a,b,c,d,e,g);k||(a.position+=b);try{if(a.path&&S.onWriteToFile)S.onWriteToFile(a.path)}catch(m){console.log("FS.trackingDelegate['onWriteToFile']('"+a.path+"') threw an exception: "+m.message)}return b}
|
||||
function Gc(){K||(K=function(a,b){this.node=b;this.zc=function(a){this.eb=a};this.zc(a);this.message="FS error";this.stack&&Object.defineProperty(this,"stack",{value:Error().stack,writable:!0})},K.prototype=Error(),K.prototype.constructor=K,[2].forEach(function(a){Eb[a]=new K(a);Eb[a].stack="<generic error, no stack>"}))}var Hc;function ia(a,b){var c=0;a&&(c|=365);b&&(c|=146);return c}
|
||||
function Ic(a,b,c){a=n("/dev",a);var d=ia(!!b,!!c);Jc||(Jc=64);var e=Jc++<<8|0;yb(e,{open:function(a){a.seekable=!1},close:function(){c&&c.buffer&&c.buffer.length&&c(10)},read:function(a,c,d,e){for(var g=0,k=0;k<e;k++){try{var m=b()}catch(Ia){throw new K(5);}if(void 0===m&&0===g)throw new K(11);if(null===m||void 0===m)break;g++;c[d+k]=m}g&&(a.node.timestamp=Date.now());return g},write:function(a,b,d,e){for(var g=0;g<e;g++)try{c(b[d+g])}catch(fa){throw new K(5);}e&&(a.node.timestamp=Date.now());return g}});
|
||||
zc(a,d,e)}
|
||||
var Jc,V={},Qb,xc,Ec,L={dc:1,bc:2,Ae:3,sd:4,Lb:5,Ob:6,Ic:7,Td:8,Kb:9,Xc:10,ac:11,Ke:11,Mb:12,$b:13,ld:14,ee:15,Vc:16,kd:17,Le:18,Cb:19,cc:20,ud:21,ib:22,Od:23,Gd:24,je:25,He:26,md:27,ae:28,ze:29,ve:30,Hd:31,pe:32,gd:33,ec:34,Xd:42,pd:43,Yc:44,wd:45,xd:46,yd:47,Ed:48,Ie:49,Rd:50,vd:51,cd:35,Ud:37,Oc:52,Rc:53,Me:54,Pd:55,Sc:56,Tc:57,dd:35,Uc:59,ce:60,Sd:61,Ee:62,be:63,Yd:64,Zd:65,ue:66,Vd:67,Lc:68,Be:69,Zc:70,qe:71,Jd:72,hd:73,Qc:74,ke:76,Pc:77,te:78,zd:79,Ad:80,Dd:81,Cd:82,Bd:83,de:38,Nb:39,Kd:36,
|
||||
Fd:40,le:95,oe:96,bd:104,Qd:105,Mc:97,se:91,he:88,$d:92,xe:108,ad:111,Jc:98,$c:103,Nd:101,Ld:100,Fe:110,nd:112,od:113,rd:115,Nc:114,ed:89,Id:90,re:93,ye:94,Kc:99,Md:102,td:106,fe:107,Ge:109,Je:87,jd:122,Ce:116,ie:95,Wd:123,qd:84,me:75,Wc:125,ge:131,ne:130,De:86},Kc={};
|
||||
function Lc(a,b,c){try{var d=a(b)}catch(e){if(e&&e.node&&rb(b)!==rb(Lb(e.node)))return-L.cc;throw e;}D[c>>2]=d.dev;D[c+4>>2]=0;D[c+8>>2]=d.ino;D[c+12>>2]=d.mode;D[c+16>>2]=d.nlink;D[c+20>>2]=d.uid;D[c+24>>2]=d.gid;D[c+28>>2]=d.rdev;D[c+32>>2]=0;D[c+36>>2]=d.size;D[c+40>>2]=4096;D[c+44>>2]=d.blocks;D[c+48>>2]=d.atime.getTime()/1E3|0;D[c+52>>2]=0;D[c+56>>2]=d.mtime.getTime()/1E3|0;D[c+60>>2]=0;D[c+64>>2]=d.ctime.getTime()/1E3|0;D[c+68>>2]=0;D[c+72>>2]=d.ino;return 0}var W=0;
|
||||
function X(){W+=4;return D[W-4>>2]}function Y(){return G(X())}function Z(){var a=Q[X()];if(!a)throw new K(L.Kb);return a}function Da(){return l.length}function Ea(a){if(2147418112<a)return!1;for(var b=Math.max(Da(),16777216);b<a;)536870912>=b?b=Wa(2*b):b=Math.min(Wa((3*b+2147483648)/4),2147418112);a=Wa(b);var c=buffer.byteLength;try{var d=-1!==La.grow((a-c)/65536)?buffer=La.buffer:null}catch(e){d=null}if(!d||d.byteLength!=b)return!1;Xa();return!0}
|
||||
function Mc(a){if(0===a)return 0;a=G(a);if(!J.hasOwnProperty(a))return 0;Mc.rb&&ha(Mc.rb);a=J[a];var b=oa(a)+1,c=Ta(b);c&&r(a,l,c,b);Mc.rb=c;return Mc.rb}r("GMT",F,60272,4);
|
||||
function Nc(){function a(a){return(a=a.toTimeString().match(/\(([A-Za-z ]+)\)$/))?a[1]:"GMT"}if(!Oc){Oc=!0;D[Pc()>>2]=60*(new Date).getTimezoneOffset();var b=new Date(2E3,0,1),c=new Date(2E3,6,1);D[Qc()>>2]=Number(b.getTimezoneOffset()!=c.getTimezoneOffset());var d=a(b),e=a(c);d=ea(ba(d));e=ea(ba(e));c.getTimezoneOffset()<b.getTimezoneOffset()?(D[Rc()>>2]=d,D[Rc()+4>>2]=e):(D[Rc()>>2]=e,D[Rc()+4>>2]=d)}}var Oc;
|
||||
function Sc(a){a/=1E3;if((v||w)&&self.performance&&self.performance.now)for(var b=self.performance.now();self.performance.now()-b<a;);else for(b=Date.now();Date.now()-b<a;);return 0}f._usleep=Sc;Gc();R=Array(4096);yc(M,"/");U("/tmp");U("/home");U("/home/web_user");
|
||||
(function(){U("/dev");yb(259,{read:function(){return 0},write:function(a,b,c,k){return k}});zc("/dev/null",259);xb(1280,Ab);xb(1536,Bb);zc("/dev/tty",1280);zc("/dev/tty1",1536);if("object"===typeof crypto&&"function"===typeof crypto.getRandomValues){var a=new Uint8Array(1);var b=function(){crypto.getRandomValues(a);return a[0]}}else if(x)try{var c=require("crypto");b=function(){return c.randomBytes(1)[0]}}catch(d){}b||(b=function(){B("random_device")});Ic("random",b);Ic("urandom",b);U("/dev/shm");
|
||||
U("/dev/shm/tmp")})();U("/proc");U("/proc/self");U("/proc/self/fd");yc({jb:function(){var a=Db("/proc/self","fd",16895,73);a.ab={lookup:function(a,c){var b=Q[+c];if(!b)throw new K(9);a={parent:null,jb:{Yb:"fake"},ab:{readlink:function(){return b.path}}};return a.parent=a}};return a}},"/proc/self/fd");if(x){var fs=require("fs"),Fb=require("path");P.Ac()}function ba(a,b){var c=Array(oa(a)+1);a=r(a,c,0,c.length);b&&(c.length=a);return c}
|
||||
var Vc=f.asm({},{n:B,l:function(a){return E[a]()},i:function(a,b){return E[a](b)},h:function(a,b,c){return E[a](b,c)},g:function(a,b,c,d){return E[a](b,c,d)},f:function(a,b,c,d,e){return E[a](b,c,d,e)},e:function(a,b,c,d,e,g){return E[a](b,c,d,e,g)},d:function(a,b,c,d,e,g,k){return E[a](b,c,d,e,g,k)},B:function(a,b,c,d,e){return E[a](b,c,d,e)},A:function(a,b,c){return E[a](b,c)},z:function(a,b,c,d){return E[a](b,c,d)},y:function(a,b,c,d,e){return E[a](b,c,d,e)},c:function(a,b){E[a](b)},b:function(a,
|
||||
b,c){E[a](b,c)},k:function(a,b,c,d){E[a](b,c,d)},j:function(a,b,c,d,e){E[a](b,c,d,e)},x:function(a,b,c,d,e,g){E[a](b,c,d,e,g)},w:function(a,b,c,d){E[a](b,c,d)},v:function(a,b,c,d){E[a](b,c,d)},m:function(a,b,c,d){B("Assertion failed: "+G(a)+", at: "+[b?G(b):"unknown filename",c,d?G(d):"unknown function"])},ga:ob,u:pb,fa:function(a,b){W=b;try{var c=Y();ta(c);return 0}catch(d){return"undefined"!==typeof V&&d instanceof K||B(d),-d.eb}},ea:function(a,b){W=b;try{return Z(),0}catch(c){return"undefined"!==
|
||||
typeof V&&c instanceof K||B(c),-c.eb}},da:function(a,b){W=b;try{var c=Z();X();var d=X(),e=X(),g=X();Fc(c,d,g);D[e>>2]=c.position;c.Gb&&0===d&&0===g&&(c.Gb=null);return 0}catch(k){return"undefined"!==typeof V&&k instanceof K||B(k),-k.eb}},ca:function(a,b){W=b;try{var c=Y(),d=X();ka(c,d);return 0}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},ba:function(a,b){W=b;try{var c=X(),d=X();if(0===d)return-L.ib;if(d<oa("/")+1)return-L.ec;r("/",F,c,d);return c}catch(e){return"undefined"!==
|
||||
typeof V&&e instanceof K||B(e),-e.eb}},aa:function(a,b){W=b;try{var c=X(),d=X(),e=X(),g=X(),k=X(),m=X();m<<=12;a=!1;if(-1===k){var y=Tc(16384,d);if(!y)return-L.Mb;Uc(y,0,d);a=!0}else{var z=Q[k];if(!z)return-L.Kb;b=F;if(1===(z.flags&2097155))throw new K(13);if(!z.cb.zb)throw new K(19);var fa=z.cb.zb(z,b,c,d,m,e,g);y=fa.xc;a=fa.Db}Kc[y]={vc:y,uc:d,Db:a,fd:k,flags:g};return y}catch(ca){return"undefined"!==typeof V&&ca instanceof K||B(ca),-ca.eb}},$:function(a,b){W=b;try{var c=X();X();var d=X();X();var e=
|
||||
Q[c];if(!e)throw new K(9);if(0===(e.flags&2097155))throw new K(22);Dc(e.node,d);return 0}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},t:function(a,b){W=b;try{var c=Y(),d=X();return Lc(ra,c,d)}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},_:function(a,b){W=b;try{var c=Y(),d=X();return Lc(Bc,c,d)}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},Z:function(a,b){W=b;try{var c=Z(),d=X();return Lc(ra,c.path,d)}catch(e){return"undefined"!==
|
||||
typeof V&&e instanceof K||B(e),-e.eb}},Y:function(a,b){W=b;return 42},X:function(a,b){W=b;return 0},W:function(a,b){W=b;try{var c=X();X();X();var d=Q[c];if(!d)throw new K(9);Cc(d.node);return 0}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},V:function(a,b){W=b;try{var c=Y();X();X();Cc(c);return 0}catch(d){return"undefined"!==typeof V&&d instanceof K||B(d),-d.eb}},o:function(a,b){W=b;try{var c=Z();switch(X()){case 0:var d=X();return 0>d?-L.ib:p(c.path,c.flags,0,d).fd;case 1:case 2:return 0;
|
||||
case 3:return c.flags;case 4:return d=X(),c.flags|=d,0;case 12:return d=X(),Ha[d+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-L.ib;case 9:return pb(L.ib),-1;default:return-L.ib}}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},U:function(a,b){W=b;try{var c=Z(),d=X(),e=X();return sa(c,l,d,e)}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},T:function(a,b){W=b;try{var c=Y();var d=X();if(d&-8)var e=-L.ib;else{var g=T(c,{qb:!0}).node;a="";d&4&&(a+="r");
|
||||
d&2&&(a+="w");d&1&&(a+="x");e=a&&Pb(g,a)?-L.$b:0}return e}catch(k){return"undefined"!==typeof V&&k instanceof K||B(k),-k.eb}},S:function(a,b){W=b;try{var c=Y(),d=X();a=c;a=rb(a);"/"===a[a.length-1]&&(a=a.substr(0,a.length-1));U(a,d);return 0}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},R:function(a,b){W=b;try{var c=Z(),d=X(),e=X();return la(c,l,d,e)}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},Q:function(a,b){W=b;try{var c=Y(),d=T(c,{parent:!0}).node,
|
||||
e=tb(c),g=O(d,e),k=uc(d,e,!0);if(k)throw new K(k);if(!d.ab.rmdir)throw new K(1);if(g.sb)throw new K(16);try{S.willDeletePath&&S.willDeletePath(c)}catch(m){console.log("FS.trackingDelegate['willDeletePath']('"+c+"') threw an exception: "+m.message)}d.ab.rmdir(d,e);Ob(g);try{if(S.onDeletePath)S.onDeletePath(c)}catch(m){console.log("FS.trackingDelegate['onDeletePath']('"+c+"') threw an exception: "+m.message)}return 0}catch(m){return"undefined"!==typeof V&&m instanceof K||B(m),-m.eb}},P:function(a,b){W=
|
||||
b;try{var c=Y(),d=X(),e=X();return p(c,d,e).fd}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},s:function(a,b){W=b;try{var c=Z();ma(c);return 0}catch(d){return"undefined"!==typeof V&&d instanceof K||B(d),-d.eb}},O:function(a,b){W=b;try{var c=Y(),d=X();var e=X();if(0>=e)var g=-L.ib;else{var k=Kb(c),m=Math.min(e,oa(k)),y=l[d+m];r(k,F,d,e+1);l[d+m]=y;g=m}return g}catch(z){return"undefined"!==typeof V&&z instanceof K||B(z),-z.eb}},N:function(a,b){W=b;try{var c=X(),d=X(),e=Kc[c];if(!e)return 0;
|
||||
if(d===e.uc){var g=Q[e.fd],k=e.flags,m=new Uint8Array(F.subarray(c,c+d));g&&g.cb.Ab&&g.cb.Ab(g,m,0,d,k);Kc[c]=null;e.Db&&ha(e.vc)}return 0}catch(y){return"undefined"!==typeof V&&y instanceof K||B(y),-y.eb}},M:function(a,b){W=b;try{var c=X(),d=X(),e=Q[c];if(!e)throw new K(9);ka(e.node,d);return 0}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},L:Da,K:function(a,b,c){F.set(F.subarray(b,b+c),a)},J:Ea,r:Mc,q:function(a){var b=Date.now();D[a>>2]=b/1E3|0;D[a+4>>2]=b%1E3*1E3|0;return 0},
|
||||
I:function(a){return Math.log(a)/Math.LN10},p:function(){B("trap!")},H:function(a){Nc();a=new Date(1E3*D[a>>2]);D[15056]=a.getSeconds();D[15057]=a.getMinutes();D[15058]=a.getHours();D[15059]=a.getDate();D[15060]=a.getMonth();D[15061]=a.getFullYear()-1900;D[15062]=a.getDay();var b=new Date(a.getFullYear(),0,1);D[15063]=(a.getTime()-b.getTime())/864E5|0;D[15065]=-(60*a.getTimezoneOffset());var c=(new Date(2E3,6,1)).getTimezoneOffset();b=b.getTimezoneOffset();a=(c!=b&&a.getTimezoneOffset()==Math.min(b,
|
||||
c))|0;D[15064]=a;a=D[Rc()+(a?4:0)>>2];D[15066]=a;return 60224},G:function(a,b){var c=D[a>>2];a=D[a+4>>2];0!==b&&(D[b>>2]=0,D[b+4>>2]=0);return Sc(1E6*c+a/1E3)},F:function(a){switch(a){case 30:return 16384;case 85:return 131068;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809;
|
||||
case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;
|
||||
case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1E3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"===typeof navigator?navigator.hardwareConcurrency||1:1}pb(22);return-1},
|
||||
E:function(a){var b=Date.now()/1E3|0;a&&(D[a>>2]=b);return b},D:function(a,b){if(b){var c=1E3*D[b+8>>2];c+=D[b+12>>2]/1E3}else c=Date.now();a=G(a);try{b=c;var d=T(a,{qb:!0}).node;d.ab.hb(d,{timestamp:Math.max(b,c)});return 0}catch(e){a=e;if(!(a instanceof K)){a+=" : ";a:{d=Error();if(!d.stack){try{throw Error(0);}catch(g){d=g}if(!d.stack){d="(no stack trace available)";break a}}d=d.stack.toString()}f.extraStackTrace&&(d+="\n"+f.extraStackTrace());d=Va(d);throw a+d;}pb(a.eb);return-1}},C:function(){B("OOM")},
|
||||
a:Ca},buffer);f.asm=Vc;f._RegisterExtensionFunctions=function(){return f.asm.ha.apply(null,arguments)};var nb=f.___emscripten_environ_constructor=function(){return f.asm.ia.apply(null,arguments)};f.___errno_location=function(){return f.asm.ja.apply(null,arguments)};
|
||||
var Qc=f.__get_daylight=function(){return f.asm.ka.apply(null,arguments)},Pc=f.__get_timezone=function(){return f.asm.la.apply(null,arguments)},Rc=f.__get_tzname=function(){return f.asm.ma.apply(null,arguments)},ha=f._free=function(){return f.asm.na.apply(null,arguments)},Ta=f._malloc=function(){return f.asm.oa.apply(null,arguments)},Tc=f._memalign=function(){return f.asm.pa.apply(null,arguments)},Uc=f._memset=function(){return f.asm.qa.apply(null,arguments)};
|
||||
f._sqlite3_bind_blob=function(){return f.asm.ra.apply(null,arguments)};f._sqlite3_bind_double=function(){return f.asm.sa.apply(null,arguments)};f._sqlite3_bind_int=function(){return f.asm.ta.apply(null,arguments)};f._sqlite3_bind_parameter_index=function(){return f.asm.ua.apply(null,arguments)};f._sqlite3_bind_text=function(){return f.asm.va.apply(null,arguments)};f._sqlite3_changes=function(){return f.asm.wa.apply(null,arguments)};f._sqlite3_clear_bindings=function(){return f.asm.xa.apply(null,arguments)};
|
||||
f._sqlite3_close_v2=function(){return f.asm.ya.apply(null,arguments)};f._sqlite3_column_blob=function(){return f.asm.za.apply(null,arguments)};f._sqlite3_column_bytes=function(){return f.asm.Aa.apply(null,arguments)};f._sqlite3_column_double=function(){return f.asm.Ba.apply(null,arguments)};f._sqlite3_column_name=function(){return f.asm.Ca.apply(null,arguments)};f._sqlite3_column_text=function(){return f.asm.Da.apply(null,arguments)};f._sqlite3_column_type=function(){return f.asm.Ea.apply(null,arguments)};
|
||||
f._sqlite3_create_function_v2=function(){return f.asm.Fa.apply(null,arguments)};f._sqlite3_data_count=function(){return f.asm.Ga.apply(null,arguments)};f._sqlite3_errmsg=function(){return f.asm.Ha.apply(null,arguments)};f._sqlite3_exec=function(){return f.asm.Ia.apply(null,arguments)};f._sqlite3_finalize=function(){return f.asm.Ja.apply(null,arguments)};f._sqlite3_free=function(){return f.asm.Ka.apply(null,arguments)};f._sqlite3_open=function(){return f.asm.La.apply(null,arguments)};
|
||||
f._sqlite3_prepare_v2=function(){return f.asm.Ma.apply(null,arguments)};f._sqlite3_reset=function(){return f.asm.Na.apply(null,arguments)};f._sqlite3_result_double=function(){return f.asm.Oa.apply(null,arguments)};f._sqlite3_result_null=function(){return f.asm.Pa.apply(null,arguments)};f._sqlite3_result_text=function(){return f.asm.Qa.apply(null,arguments)};f._sqlite3_step=function(){return f.asm.Ra.apply(null,arguments)};f._sqlite3_value_blob=function(){return f.asm.Sa.apply(null,arguments)};
|
||||
f._sqlite3_value_bytes=function(){return f.asm.Ta.apply(null,arguments)};f._sqlite3_value_double=function(){return f.asm.Ua.apply(null,arguments)};f._sqlite3_value_int=function(){return f.asm.Va.apply(null,arguments)};f._sqlite3_value_text=function(){return f.asm.Wa.apply(null,arguments)};f._sqlite3_value_type=function(){return f.asm.Xa.apply(null,arguments)};
|
||||
var h=f.stackAlloc=function(){return f.asm.Za.apply(null,arguments)},qa=f.stackRestore=function(){return f.asm._a.apply(null,arguments)},na=f.stackSave=function(){return f.asm.$a.apply(null,arguments)};f.dynCall_vi=function(){return f.asm.Ya.apply(null,arguments)};f.asm=Vc;f.cwrap=function(a,b,c,d){c=c||[];var e=c.every(function(a){return"number"===a});return"string"!==b&&e&&!d?Na(a):function(){return Oa(a,b,c,arguments)}};f.stackSave=na;f.stackRestore=qa;f.stackAlloc=h;
|
||||
function Wc(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Wc.prototype=Error();Wc.prototype.constructor=Wc;gb=function Xc(){f.calledRun||Yc();f.calledRun||(gb=Xc)};
|
||||
function Yc(){function a(){if(!f.calledRun&&(f.calledRun=!0,!Ma)){db||(db=!0,f.noFSInit||Hc||(Hc=!0,Gc(),f.stdin=f.stdin,f.stdout=f.stdout,f.stderr=f.stderr,f.stdin?Ic("stdin",f.stdin):Ac("/dev/tty","/dev/stdin"),f.stdout?Ic("stdout",null,f.stdout):Ac("/dev/tty","/dev/stdout"),f.stderr?Ic("stderr",null,f.stderr):Ac("/dev/tty1","/dev/stderr"),p("/dev/stdin","r"),p("/dev/stdout","w"),p("/dev/stderr","w")),Za(ab));Jb=!1;Za(bb);if(f.onRuntimeInitialized)f.onRuntimeInitialized();if(f.postRun)for("function"==
|
||||
typeof f.postRun&&(f.postRun=[f.postRun]);f.postRun.length;){var a=f.postRun.shift();cb.unshift(a)}Za(cb)}}if(!(0<H)){if(f.preRun)for("function"==typeof f.preRun&&(f.preRun=[f.preRun]);f.preRun.length;)eb();Za($a);0<H||f.calledRun||(f.setStatus?(f.setStatus("Running..."),setTimeout(function(){setTimeout(function(){f.setStatus("")},1);a()},1)):a())}}f.run=Yc;
|
||||
function B(a){if(f.onAbort)f.onAbort(a);void 0!==a?(Aa(a),C(a),a=JSON.stringify(a)):a="";Ma=!0;throw"abort("+a+"). Build with -s ASSERTIONS=1 for more info.";}f.abort=B;if(f.preInit)for("function"==typeof f.preInit&&(f.preInit=[f.preInit]);0<f.preInit.length;)f.preInit.pop()();f.noExitRuntime=!0;Yc();
|
||||
|
||||
|
||||
// The shell-pre.js and emcc-generated code goes above
|
||||
return Module;
|
||||
}); // The end of the promise being returned
|
||||
|
||||
return initSqlJsPromise;
|
||||
} // The end of our initSqlJs function
|
||||
|
||||
// This bit below is copied almost exactly from what you get when you use the MODULARIZE=1 flag with emcc
|
||||
// However, we don't want to use the emcc modularization. See shell-pre.js
|
||||
if (typeof exports === 'object' && typeof module === 'object'){
|
||||
module.exports = initSqlJs;
|
||||
// This will allow the module to be used in ES6 or CommonJS
|
||||
module.exports.default = initSqlJs;
|
||||
}
|
||||
else if (typeof define === 'function' && define['amd']) {
|
||||
define([], function() { return initSqlJs; });
|
||||
}
|
||||
else if (typeof exports === 'object'){
|
||||
exports["Module"] = initSqlJs;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
class AttachmentActions extends StatelessWidget {
|
||||
final Attachment attachment;
|
||||
final Message message;
|
||||
|
||||
const AttachmentActions({
|
||||
Key key,
|
||||
this.attachment,
|
||||
this.message,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final streamChannel = StreamChannel.of(context);
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: attachment.actions?.map((action) {
|
||||
if (action.style == 'primary') {
|
||||
return FlatButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text('${action.text}'),
|
||||
color: action.style == 'primary'
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: null,
|
||||
textColor: Colors.white,
|
||||
onPressed: () {
|
||||
streamChannel.channel.sendAction(message, {
|
||||
action.name: action.value,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
return OutlineButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text('${action.text}'),
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
onPressed: () {
|
||||
streamChannel.channel.sendAction(message, {
|
||||
action.name: action.value,
|
||||
});
|
||||
},
|
||||
);
|
||||
})?.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StreamBackButton extends StatelessWidget {
|
||||
const StreamBackButton({
|
||||
Key key,
|
||||
this.onPressed,
|
||||
this.icon = Icons.arrow_back_ios_outlined,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final IconData icon;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(14.0),
|
||||
child: RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: () {
|
||||
if (onPressed != null) {
|
||||
onPressed();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
fillColor: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white.withOpacity(.1)
|
||||
: Colors.black.withOpacity(.1),
|
||||
child: Icon(
|
||||
icon ?? Icons.arrow_back_ios_outlined,
|
||||
size: 15,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/back_button.dart';
|
||||
import 'package:stream_chat_flutter/src/channel_name.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
import './channel_name.dart';
|
||||
import 'channel_image.dart';
|
||||
import 'stream_channel.dart';
|
||||
|
||||
/// 
|
||||
/// 
|
||||
///
|
||||
/// It shows the current [Channel] information.
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyApp extends StatelessWidget {
|
||||
/// final Client client;
|
||||
/// final Channel channel;
|
||||
///
|
||||
/// MyApp(this.client, this.channel);
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return MaterialApp(
|
||||
/// home: StreamChat(
|
||||
/// client: client,
|
||||
/// child: StreamChannel(
|
||||
/// channel: channel,
|
||||
/// child: Scaffold(
|
||||
/// appBar: ChannelHeader(),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Usually you would use this widget as an [AppBar] inside a [Scaffold].
|
||||
/// However you can also use it as a normal widget.
|
||||
///
|
||||
/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channel.
|
||||
/// Every part of the widget uses a [StreamBuilder] to render the channel information as soon as it updates.
|
||||
///
|
||||
/// By default the widget shows a backButton that calls [Navigator.pop].
|
||||
/// You can disable this button using the [showBackButton] property of just override the behaviour
|
||||
/// with [onBackPressed].
|
||||
///
|
||||
/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
||||
/// Modify it to change the widget appearance.
|
||||
class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
/// True if this header shows the leading back button
|
||||
final bool showBackButton;
|
||||
|
||||
/// Callback to call when pressing the back button.
|
||||
/// By default it calls [Navigator.pop]
|
||||
final VoidCallback onBackPressed;
|
||||
|
||||
/// Callback to call when the header is tapped.
|
||||
final VoidCallback onTitleTap;
|
||||
|
||||
/// Callback to call when the image is tapped.
|
||||
final VoidCallback onImageTap;
|
||||
|
||||
/// Creates a channel header
|
||||
ChannelHeader({
|
||||
Key key,
|
||||
this.showBackButton = true,
|
||||
this.onBackPressed,
|
||||
this.onTitleTap,
|
||||
this.onImageTap,
|
||||
}) : preferredSize = Size.fromHeight(kToolbarHeight),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
return AppBar(
|
||||
elevation: 1,
|
||||
leading: showBackButton
|
||||
? StreamBackButton(onPressed: onBackPressed)
|
||||
: SizedBox(),
|
||||
backgroundColor:
|
||||
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
|
||||
actions: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
child: Center(
|
||||
child: ChannelImage(
|
||||
onTap: onImageTap,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
centerTitle: true,
|
||||
title: InkWell(
|
||||
onTap: onTitleTap,
|
||||
child: Container(
|
||||
height: preferredSize.height,
|
||||
width: preferredSize.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
ChannelName(
|
||||
textStyle: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.title,
|
||||
),
|
||||
_buildLastActive(context, channel),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLastActive(BuildContext context, Channel channel) {
|
||||
return StreamBuilder<DateTime>(
|
||||
stream: channel.lastMessageAtStream,
|
||||
initialData: channel.lastMessageAt,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
final jiffyDate = Jiffy(snapshot.data?.toLocal());
|
||||
return Text(
|
||||
'Active ${jiffyDate.isBefore(Jiffy()) ? jiffyDate.fromNow() : 'now'}',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.lastMessageAt,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
final Size preferredSize;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
import 'stream_channel.dart';
|
||||
|
||||
/// It shows the current [Channel] name using a [Text] widget.
|
||||
///
|
||||
/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates.
|
||||
class ChannelName extends StatelessWidget {
|
||||
/// Instantiate a new ChannelName
|
||||
const ChannelName({
|
||||
Key key,
|
||||
this.channel,
|
||||
this.textStyle,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The channel to show the name of
|
||||
final Channel channel;
|
||||
|
||||
/// The style of the text displayed
|
||||
final TextStyle textStyle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final client = StreamChat.of(context);
|
||||
final channel = this.channel ?? StreamChannel.of(context).channel;
|
||||
return StreamBuilder<Map<String, dynamic>>(
|
||||
stream: channel.extraDataStream,
|
||||
initialData: channel.extraData,
|
||||
builder: (context, snapshot) {
|
||||
String title;
|
||||
if (snapshot.data['name'] == null &&
|
||||
channel.state.members.length == 2) {
|
||||
final otherMember = channel.state.members
|
||||
.firstWhere((member) => member.user.id != client.user.id);
|
||||
title = otherMember.user.name;
|
||||
} else {
|
||||
title = snapshot.data['name'] ?? channel.id;
|
||||
}
|
||||
|
||||
return Text(
|
||||
title,
|
||||
style: textStyle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
|
||||
/// It shows a date divider depending on the date difference
|
||||
class DateDivider extends StatelessWidget {
|
||||
final DateTime dateTime;
|
||||
|
||||
const DateDivider({
|
||||
Key key,
|
||||
@required this.dateTime,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final divider = Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
);
|
||||
|
||||
final createdAt = Jiffy(dateTime);
|
||||
final now = DateTime.now();
|
||||
final hourInfo = createdAt.format('h:mm a');
|
||||
|
||||
String dayInfo;
|
||||
if (Jiffy(createdAt).isSame(now, Units.DAY)) {
|
||||
dayInfo = 'TODAY';
|
||||
} else if (Jiffy(createdAt)
|
||||
.isSame(now.subtract(Duration(days: 1)), Units.DAY)) {
|
||||
dayInfo = 'YESTERDAY';
|
||||
} else if (Jiffy(createdAt).isAfter(
|
||||
now.subtract(Duration(days: 7)),
|
||||
Units.DAY,
|
||||
)) {
|
||||
dayInfo = createdAt.format('EEEE').toUpperCase();
|
||||
} else if (Jiffy(createdAt).isAfter(
|
||||
Jiffy(now).subtract(years: 1),
|
||||
Units.DAY,
|
||||
)) {
|
||||
dayInfo = createdAt.format('dd/MM').toUpperCase();
|
||||
} else {
|
||||
dayInfo = createdAt.format('dd/MM/yyyy').toUpperCase();
|
||||
}
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
divider,
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32.0),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: dayInfo,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' AT'),
|
||||
TextSpan(text: ' $hourInfo'),
|
||||
],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color:
|
||||
Theme.of(context).textTheme.headline6.color.withOpacity(.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
divider,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
class DeletedMessage extends StatelessWidget {
|
||||
const DeletedMessage({
|
||||
Key key,
|
||||
@required this.messageTheme,
|
||||
}) : super(key: key);
|
||||
|
||||
final MessageTheme messageTheme;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
'This message was deleted...',
|
||||
style: messageTheme.messageText.copyWith(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/utils.dart';
|
||||
|
||||
class FileAttachment extends StatelessWidget {
|
||||
final Attachment attachment;
|
||||
final Size size;
|
||||
|
||||
const FileAttachment({
|
||||
Key key,
|
||||
@required this.attachment,
|
||||
this.size,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
launchURL(context, attachment.assetUrl);
|
||||
},
|
||||
child: Container(
|
||||
width: size?.width ?? 100,
|
||||
height: size?.height ?? 100,
|
||||
child: Center(
|
||||
child: Icon(Icons.attach_file),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
|
||||
/// A full screen image widget
|
||||
class FullScreenImage extends StatelessWidget {
|
||||
/// The url of the image
|
||||
final String url;
|
||||
|
||||
/// Instantiate a new FullScreenImage
|
||||
const FullScreenImage({
|
||||
Key key,
|
||||
@required this.url,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
body: PhotoView(
|
||||
imageProvider: CachedNetworkImageProvider(url),
|
||||
maxScale: PhotoViewComputedScale.covered,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
heroAttributes: PhotoViewHeroAttributes(
|
||||
tag: url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import 'package:chewie/chewie.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
class FullScreenVideo extends StatefulWidget {
|
||||
final Attachment attachment;
|
||||
|
||||
FullScreenVideo({
|
||||
Key key,
|
||||
@required this.attachment,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_FullScreenVideoState createState() => _FullScreenVideoState();
|
||||
}
|
||||
|
||||
class _FullScreenVideoState extends State<FullScreenVideo> {
|
||||
ChewieController _chewieController;
|
||||
VideoPlayerController _videoPlayerController;
|
||||
bool initialized = false;
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
body: Builder(
|
||||
key: _scaffoldKey,
|
||||
builder: (context) {
|
||||
if (!initialized) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
return Chewie(
|
||||
controller: _chewieController,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_videoPlayerController =
|
||||
VideoPlayerController.network(widget.attachment.assetUrl);
|
||||
_videoPlayerController.initialize().whenComplete(() {
|
||||
setState(() {
|
||||
initialized = true;
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
autoInitialize: false,
|
||||
aspectRatio: _videoPlayerController.value.aspectRatio,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
VoidCallback errorListener;
|
||||
errorListener = () {
|
||||
if (_videoPlayerController.value.hasError) {
|
||||
Navigator.pop(context);
|
||||
launchURL(_scaffoldKey.currentContext, widget.attachment.titleLink);
|
||||
}
|
||||
_videoPlayerController.removeListener(errorListener);
|
||||
};
|
||||
_videoPlayerController.addListener(errorListener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_videoPlayerController?.dispose();
|
||||
_chewieController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment_actions.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
import 'attachment_error.dart';
|
||||
import 'attachment_title.dart';
|
||||
import 'full_screen_image.dart';
|
||||
|
||||
class GiphyAttachment extends StatelessWidget {
|
||||
final Attachment attachment;
|
||||
final MessageTheme messageTheme;
|
||||
final Message message;
|
||||
final Size size;
|
||||
|
||||
const GiphyAttachment({
|
||||
Key key,
|
||||
this.attachment,
|
||||
this.messageTheme,
|
||||
this.message,
|
||||
this.size,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (attachment.thumbUrl == null &&
|
||||
attachment.imageUrl == null &&
|
||||
attachment.assetUrl == null) {
|
||||
return AttachmentError(
|
||||
attachment: attachment,
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Stack(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) {
|
||||
return FullScreenImage(
|
||||
url: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl,
|
||||
);
|
||||
}));
|
||||
},
|
||||
child: CachedNetworkImage(
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
placeholder: (_, __) {
|
||||
return Container(
|
||||
width: size?.width,
|
||||
height: size?.height,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
},
|
||||
imageUrl: attachment.thumbUrl ??
|
||||
attachment.imageUrl ??
|
||||
attachment.assetUrl,
|
||||
errorWidget: (context, url, error) => AttachmentError(
|
||||
attachment: attachment,
|
||||
size: size,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (attachment.title != null)
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Material(
|
||||
color: messageTheme.messageBackgroundColor,
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (attachment.actions != null)
|
||||
AttachmentActions(
|
||||
attachment: attachment,
|
||||
message: message,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/reaction_picker.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_channel.dart';
|
||||
import 'package:stream_chat_flutter/src/user_reaction_display.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
import 'message_input.dart';
|
||||
import 'stream_chat.dart';
|
||||
|
||||
class MessageActionsBottomSheet extends StatelessWidget {
|
||||
final Widget Function(BuildContext, Message) editMessageInputBuilder;
|
||||
final void Function(Message) onThreadTap;
|
||||
final Message message;
|
||||
final bool showReactions;
|
||||
final bool showDeleteMessage;
|
||||
final bool showEditMessage;
|
||||
final bool showReply;
|
||||
final Map<String, String> reactionToEmoji = const {
|
||||
'love': '❤️️',
|
||||
'haha': '😂',
|
||||
'like': '👍',
|
||||
'sad': '😕',
|
||||
'angry': '😡',
|
||||
'wow': '😲',
|
||||
};
|
||||
|
||||
const MessageActionsBottomSheet({
|
||||
Key key,
|
||||
this.message,
|
||||
this.showReactions,
|
||||
this.showDeleteMessage,
|
||||
this.showEditMessage,
|
||||
this.onThreadTap,
|
||||
this.showReply,
|
||||
this.editMessageInputBuilder,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
if (showReactions &&
|
||||
(message.status == MessageSendingStatus.SENT ||
|
||||
message.status == null) &&
|
||||
message.latestReactions.isNotEmpty)
|
||||
UserReactionDisplay(
|
||||
reactionToEmoji: reactionToEmoji,
|
||||
message: message,
|
||||
),
|
||||
if (showReactions &&
|
||||
(message.status == MessageSendingStatus.SENT ||
|
||||
message.status == null))
|
||||
ReactionPicker(
|
||||
channel: channel,
|
||||
reactionToEmoji: reactionToEmoji,
|
||||
message: message,
|
||||
),
|
||||
if (showDeleteMessage) _buildDeleteButton(context),
|
||||
if (showEditMessage) _buildEditMessage(context),
|
||||
if (showReply &&
|
||||
(message.status == MessageSendingStatus.SENT ||
|
||||
message.status == null) &&
|
||||
message.parentId == null)
|
||||
_buildReplyButton(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FlatButton _buildDeleteButton(BuildContext context) {
|
||||
return FlatButton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Delete message',
|
||||
style:
|
||||
Theme.of(context).textTheme.headline5.copyWith(color: Colors.red),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
StreamChat.of(context).client.deleteMessage(
|
||||
message,
|
||||
StreamChannel.of(context).channel.cid,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
FlatButton _buildEditMessage(BuildContext context) {
|
||||
return FlatButton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Edit message',
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
_showEditBottomSheet(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showEditBottomSheet(BuildContext context) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
elevation: 2,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(32),
|
||||
topRight: Radius.circular(32),
|
||||
),
|
||||
),
|
||||
builder: (context) {
|
||||
return StreamChannel(
|
||||
channel: channel,
|
||||
child: Flex(
|
||||
direction: Axis.vertical,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16.0,
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Edit message',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
Container(
|
||||
height: 30,
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fillColor:
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white.withOpacity(.1)
|
||||
: Colors.black.withOpacity(.1),
|
||||
padding: EdgeInsets.all(4),
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 15,
|
||||
color: StreamChatTheme.of(context)
|
||||
.primaryIconTheme
|
||||
.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: editMessageInputBuilder != null
|
||||
? editMessageInputBuilder(context, message)
|
||||
: MessageInput(
|
||||
editMessage: message,
|
||||
onMessageSent: (_) {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
FlatButton _buildReplyButton(BuildContext context) {
|
||||
return FlatButton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Start a thread',
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
if (onThreadTap != null) {
|
||||
onThreadTap(message);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// A reply button indicator
|
||||
class ReplyIndicator extends StatelessWidget {
|
||||
final Message message;
|
||||
final VoidCallback onTap;
|
||||
final bool reversed;
|
||||
final MessageTheme messageTheme;
|
||||
|
||||
const ReplyIndicator({
|
||||
Key key,
|
||||
this.message,
|
||||
this.onTap,
|
||||
this.reversed = false,
|
||||
this.messageTheme,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var row = [
|
||||
Text(
|
||||
'Replies: ${message.replyCount}',
|
||||
style: messageTheme?.replies,
|
||||
),
|
||||
Transform(
|
||||
transform: Matrix4.rotationY(reversed ? 0 : pi),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
Icons.subdirectory_arrow_left,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white12
|
||||
: Colors.black12,
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (!reversed) {
|
||||
row = row.reversed.toList();
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: row,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Used to show the sending status of the message
|
||||
class SendingIndicator extends StatelessWidget {
|
||||
final Message message;
|
||||
|
||||
const SendingIndicator({
|
||||
Key key,
|
||||
this.message,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (message.status == MessageSendingStatus.SENT || message.status == null) {
|
||||
return CircleAvatar(
|
||||
radius: 4,
|
||||
backgroundColor: StreamChatTheme.of(context).accentColor,
|
||||
child: Icon(
|
||||
Icons.done,
|
||||
color: Colors.white,
|
||||
size: 4,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (message.status == MessageSendingStatus.SENDING ||
|
||||
message.status == MessageSendingStatus.UPDATING) {
|
||||
return CircleAvatar(
|
||||
radius: 4,
|
||||
backgroundColor: Colors.grey,
|
||||
child: Icon(
|
||||
Icons.access_time,
|
||||
size: 4,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (message.status == MessageSendingStatus.FAILED ||
|
||||
message.status == MessageSendingStatus.FAILED_UPDATE ||
|
||||
message.status == MessageSendingStatus.FAILED_DELETE) {
|
||||
return CircleAvatar(
|
||||
radius: 4,
|
||||
backgroundColor: Color(0xffd0021B).withOpacity(.1),
|
||||
child: Icon(
|
||||
Icons.error_outline,
|
||||
size: 4,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox();
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
|
||||
/// Widget used to provide information about the channel to the widget tree
|
||||
///
|
||||
/// Use [StreamChannel.of] to get the current [StreamChannelState] instance.
|
||||
class StreamChannel extends StatefulWidget {
|
||||
StreamChannel({
|
||||
Key key,
|
||||
@required this.child,
|
||||
@required this.channel,
|
||||
}) : super(
|
||||
key: key,
|
||||
);
|
||||
|
||||
final Widget child;
|
||||
final Channel channel;
|
||||
|
||||
/// Use this method to get the current [StreamChannelState] instance
|
||||
static StreamChannelState of(BuildContext context) {
|
||||
StreamChannelState streamChannelState;
|
||||
|
||||
streamChannelState = context.findAncestorStateOfType<StreamChannelState>();
|
||||
|
||||
if (streamChannelState == null) {
|
||||
throw Exception(
|
||||
'You must have a StreamChannel widget at the top of your widget tree');
|
||||
}
|
||||
|
||||
return streamChannelState;
|
||||
}
|
||||
|
||||
@override
|
||||
StreamChannelState createState() => StreamChannelState();
|
||||
}
|
||||
|
||||
class StreamChannelState extends State<StreamChannel> {
|
||||
/// Current channel
|
||||
Channel get channel => widget.channel;
|
||||
|
||||
/// Current channel state stream
|
||||
Stream<ChannelState> get channelStateStream =>
|
||||
widget.channel.state.channelStateStream;
|
||||
|
||||
final BehaviorSubject<bool> _queryMessageController = BehaviorSubject();
|
||||
|
||||
/// The stream notifying the state of queryMessage call
|
||||
Stream<bool> get queryMessage => _queryMessageController.stream;
|
||||
|
||||
bool _paginationEnded = false;
|
||||
|
||||
/// Calls [channel.query] updating [queryMessage] stream
|
||||
void queryMessages() {
|
||||
if (_queryMessageController.value == true || _paginationEnded) {
|
||||
return;
|
||||
}
|
||||
|
||||
_queryMessageController.add(true);
|
||||
|
||||
String firstId;
|
||||
if (channel.state.messages.isNotEmpty) {
|
||||
firstId = channel.state.messages.first.id;
|
||||
}
|
||||
|
||||
final messageLimit = 50;
|
||||
|
||||
widget.channel
|
||||
.query(
|
||||
messagesPagination: PaginationParams(
|
||||
lessThan: firstId,
|
||||
limit: messageLimit,
|
||||
),
|
||||
preferOffline: true,
|
||||
)
|
||||
.then((res) {
|
||||
if (res.messages.isEmpty || res.messages.length < messageLimit) {
|
||||
_paginationEnded = true;
|
||||
}
|
||||
_queryMessageController.add(false);
|
||||
}).catchError((e, stack) {
|
||||
_queryMessageController.addError(e, stack);
|
||||
});
|
||||
}
|
||||
|
||||
/// Calls [channel.getReplies] updating [queryMessage] stream
|
||||
Future<void> getReplies(String parentId) async {
|
||||
if (_queryMessageController.value == true || _paginationEnded) {
|
||||
return;
|
||||
}
|
||||
|
||||
_queryMessageController.add(true);
|
||||
|
||||
String firstId;
|
||||
if (widget.channel.state.threads.containsKey(parentId)) {
|
||||
final thread = widget.channel.state.threads[parentId];
|
||||
|
||||
if (thread != null && thread.isNotEmpty) {
|
||||
firstId = thread?.first?.id;
|
||||
}
|
||||
}
|
||||
|
||||
final messageLimit = 50;
|
||||
return widget.channel
|
||||
.getReplies(
|
||||
parentId,
|
||||
PaginationParams(
|
||||
lessThan: firstId,
|
||||
limit: messageLimit,
|
||||
),
|
||||
preferOffline: true,
|
||||
)
|
||||
.then((res) {
|
||||
if (res.messages.isEmpty || res.messages.length < messageLimit) {
|
||||
_paginationEnded = true;
|
||||
}
|
||||
_queryMessageController.add(false);
|
||||
}).catchError((e, stack) {
|
||||
_queryMessageController.addError(e, stack);
|
||||
});
|
||||
}
|
||||
|
||||
/// Query the channel members and watchers
|
||||
Future<void> queryMembersAndWatchers() async {
|
||||
await widget.channel.query(
|
||||
membersPagination: PaginationParams(
|
||||
offset: channel.state.members?.length,
|
||||
limit: 100,
|
||||
),
|
||||
watchersPagination: PaginationParams(
|
||||
offset: channel.state.watchers?.length,
|
||||
limit: 100,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_queryMessageController.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.channel == null) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
return FutureBuilder<bool>(
|
||||
future: widget.channel.initialized,
|
||||
initialData: widget.channel.state != null,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || !snapshot.data) {
|
||||
return Container(
|
||||
height: 30,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return Container(
|
||||
height: 30,
|
||||
child: Center(
|
||||
child: Text(snapshot.error),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return widget.child;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
class UnreadIndicator extends StatelessWidget {
|
||||
const UnreadIndicator({
|
||||
Key key,
|
||||
@required this.channel,
|
||||
}) : super(key: key);
|
||||
|
||||
final Channel channel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<int>(
|
||||
stream: channel.state.unreadCountStream,
|
||||
initialData: channel.state.unreadCount,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || snapshot.data == 0) {
|
||||
return SizedBox();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: StreamChatTheme.of(context)
|
||||
.channelPreviewTheme
|
||||
.unreadCounterColor,
|
||||
radius: 6,
|
||||
child: Text(
|
||||
'${snapshot.data}',
|
||||
style: TextStyle(fontSize: 8),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
|
||||
class UserAvatar extends StatelessWidget {
|
||||
const UserAvatar({
|
||||
Key key,
|
||||
@required this.user,
|
||||
this.constraints,
|
||||
this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final User user;
|
||||
final BoxConstraints constraints;
|
||||
final void Function(User) onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hasImage = user.extraData?.containsKey('image') == true &&
|
||||
user.extraData['image'] != null &&
|
||||
user.extraData['image'] != '';
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (onTap != null) {
|
||||
onTap(user);
|
||||
}
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: StreamChatTheme.of(context)
|
||||
.ownMessageTheme
|
||||
.avatarTheme
|
||||
.borderRadius,
|
||||
child: Container(
|
||||
constraints: constraints ??
|
||||
StreamChatTheme.of(context)
|
||||
.ownMessageTheme
|
||||
.avatarTheme
|
||||
.constraints,
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
),
|
||||
child: hasImage
|
||||
? CachedNetworkImage(
|
||||
imageUrl: user.extraData['image'],
|
||||
errorWidget: (_, __, ___) {
|
||||
return Center(
|
||||
child: Text(
|
||||
user.extraData?.containsKey('name') ?? false
|
||||
? user.extraData['name'][0]
|
||||
: '',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: StreamChatTheme.of(context).defaultUserImage(context, user),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
Future<void> launchURL(BuildContext context, String url) async {
|
||||
if (await canLaunch(url)) {
|
||||
await launch(url);
|
||||
} else {
|
||||
Scaffold.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Cannot launch the url'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
name: stream_chat_dart
|
||||
|
||||
versioning:
|
||||
mode: independent
|
||||
|
||||
packages:
|
||||
- packages/**
|
||||
|
||||
scripts:
|
||||
|
||||
# - Requires `pub global activate tuneup`.
|
||||
analyze: >
|
||||
melos exec -c 1 --fail-fast -- \
|
||||
pub global run tuneup check
|
||||
|
||||
format: pub global run flutter_plugin_tools format
|
||||
|
||||
|
||||
build:examples:ios: >
|
||||
melos exec -c 1 --scope="*example*" --fail-fast -- \
|
||||
flutter build ios --no-codesign
|
||||
|
||||
|
||||
build:examples:android: >
|
||||
melos exec -c 1 --scope="*example*" --fail-fast -- \
|
||||
flutter build apk
|
||||
|
||||
# Build any plugin example apps that have MacOS support.
|
||||
# - Requires `flutter config --enable-macos-desktop` enabled.
|
||||
# - Requires `flutter channel master && flutter upgrade`.
|
||||
build:examples:macos: >
|
||||
melos exec -c 1 --scope="*example*" --dir-exists=macos --fail-fast -- \
|
||||
flutter build macos
|
||||
|
||||
|
||||
test:dart: >
|
||||
melos exec -c 1 --fail-fast --no-flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \
|
||||
flutter pub run test
|
||||
|
||||
test:flutter: >
|
||||
melos exec -c 1 --fail-fast --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \
|
||||
flutter test
|
||||
|
||||
test:web: >
|
||||
melos exec -c 1 --fail-fast --dir-exists=test --scope="*web*" -- \
|
||||
flutter test --platform=chrome
|
||||
|
||||
|
||||
lint:pub: >
|
||||
melos exec -c 5 --fail-fast --no-private --ignore="*example*" -- \
|
||||
pub publish --dry-run
|
||||
|
||||
|
||||
postclean: >
|
||||
melos exec -- \
|
||||
rm -rf ./build ./android/.gradle ./ios/.symlinks ./ios/Pods ./android/.idea ./.idea ./.dart-tool/build
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: 1.9.2
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
flutter: ">=1.22.4 <2.0.0"
|
||||
@@ -0,0 +1,60 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
coverage/
|
||||
coverage_helper_test.dart
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Exceptions to above rules.
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
|
||||
# Files and directories created by pub
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
|
||||
# Avoid committing generated Javascript files:
|
||||
*.dart.js
|
||||
*.info.json # Produced by the --dump-info flag.
|
||||
*.js # When generated by dart2js. Don't specify *.js if your
|
||||
# project includes source files written in JavaScript.
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
@@ -0,0 +1,10 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 659dc8129d4edb9166e9a0d600439d135740933f
|
||||
channel: beta
|
||||
|
||||
project_type: package
|
||||
@@ -0,0 +1,459 @@
|
||||
## 1.0.1-beta
|
||||
|
||||
- Fixed pub analysis issues
|
||||
|
||||
## 1.0.0-beta
|
||||
|
||||
- 🛑 **BREAKING** Renamed `Client` to less generic `StreamChatClient`
|
||||
- 🛑 **BREAKING** Segregated the persistence layer into separate package [stream_chat_persistence](https://pub.dev/packages/stream_chat_persistence)
|
||||
- 🛑 **BREAKING** Moved `Client.backgroundKeepAlive` to [core package](https://pub.dev/packages/stream_chat_core)
|
||||
- 🛑 **BREAKING** Moved `Client.showLocalNotification` to [core package](https://pub.dev/packages/stream_chat_core) and renamed it to `StreamChatCore.onBackgroundEventReceived`
|
||||
- Removed `flutter` dependency. This is now a pure Dart package 🥳
|
||||
- Minor improvements and bugfixes
|
||||
|
||||
## 0.2.24+2
|
||||
|
||||
- Fix reconnection bug while using tokenProvider
|
||||
|
||||
## 0.2.24+1
|
||||
|
||||
- Stop ws reconnection after calling disconnect
|
||||
|
||||
## 0.2.24
|
||||
|
||||
- Create enum for push providers
|
||||
- Add merge helper functions in `Message` and `ChannelModel` for easier data manipulation
|
||||
|
||||
## 0.2.23+3
|
||||
|
||||
- Remove + notation from userAgent
|
||||
- Fix optimistic update for totalUnreadCount
|
||||
|
||||
## 0.2.23+2
|
||||
|
||||
- Do not throw an error when calling queryChannels without an active connection if the offline storage is enabled
|
||||
|
||||
## 0.2.23+1
|
||||
|
||||
- Throw an error when calling queryChannels without an active connection
|
||||
- Wait to establish a connection if calling queryChannels while connecting
|
||||
|
||||
## 0.2.23
|
||||
|
||||
- Add thread_participants in message model
|
||||
|
||||
## 0.2.22
|
||||
|
||||
- Add thread-less message reply feature (QuotedMessage)
|
||||
|
||||
## 0.2.21+2
|
||||
|
||||
- Fix but not throwing error during querychannels and persistance disabled
|
||||
- Fix reaction.updated event handling
|
||||
|
||||
## 0.2.21+1
|
||||
|
||||
- Fix error in the offline storage queryChannelCids query
|
||||
|
||||
## 0.2.21
|
||||
|
||||
- Fix channel.hide(clearHistory: true) not clearing local messages
|
||||
- Add banned field to member
|
||||
|
||||
## 0.2.20
|
||||
|
||||
- Return offline data only if the backend is unreachable. This avoids the glitch of the ChannelListView because we cannot sort by custom properties.
|
||||
|
||||
## 0.2.19
|
||||
|
||||
- Added message filters for `Client.search()`
|
||||
|
||||
## 0.2.18
|
||||
|
||||
- Correctly dispose resources when disposing the client state
|
||||
- Limit parallel queryChannels with same parameters to 1
|
||||
- Added `clearUser` parameter to `client.disconnect` to remove the user instance of the client
|
||||
|
||||
## 0.2.17+1
|
||||
|
||||
- Do not retry messages when server returns error
|
||||
|
||||
## 0.2.17
|
||||
|
||||
- Add shadow ban feature
|
||||
|
||||
## 0.2.16
|
||||
|
||||
- Listen for user.updated events
|
||||
|
||||
## 0.2.15+2
|
||||
|
||||
- Fix reaction score updates
|
||||
|
||||
## 0.2.15+1
|
||||
|
||||
- Listen to reaction.updated event
|
||||
|
||||
## 0.2.15
|
||||
|
||||
- Fix search message response
|
||||
|
||||
## 0.2.14
|
||||
|
||||
- Add event.extradata
|
||||
|
||||
## 0.2.13+1
|
||||
|
||||
- Let user change channel.extradata if the channel is not initialized yet
|
||||
|
||||
## 0.2.13
|
||||
|
||||
- Add parent_id to events for typing indicators in threads
|
||||
|
||||
## 0.2.12+2
|
||||
|
||||
- Fix error with reactions with null user
|
||||
|
||||
## 0.2.12
|
||||
|
||||
- Do not save channels in memory if not being watched. This was leading to some bugs in some specific use-cases.
|
||||
|
||||
## 0.2.11
|
||||
|
||||
- Fix user.name getter
|
||||
- Use detached loggers
|
||||
- Throw error while connecting if it comes from backend
|
||||
- Fix ws reconnection
|
||||
|
||||
## 0.2.10+2
|
||||
|
||||
- Fix bug with event filtering
|
||||
|
||||
## 0.2.10+1
|
||||
|
||||
- Add default limit to pagination
|
||||
|
||||
## 0.2.10
|
||||
|
||||
- Added `channel.state.unreadCountStream`
|
||||
|
||||
## 0.2.9
|
||||
|
||||
- Adding a message on `Channel.update` is now optional
|
||||
|
||||
## 0.2.8+1
|
||||
|
||||
- Fix retry logic
|
||||
|
||||
## 0.2.8
|
||||
|
||||
- Add missing event types
|
||||
- Fix local sorting on offline storage
|
||||
|
||||
## 0.2.7+1
|
||||
|
||||
- `Client.channel` returns an existing channel if available
|
||||
- Update message in the offline storage if attachment has expired (for the new CDN)
|
||||
- Fix `GetMessagesByIdResponse` format
|
||||
- Do not query messages if already existing in offline storage
|
||||
|
||||
## 0.2.6
|
||||
|
||||
- Experimental support for Flutter web and MacOs
|
||||
|
||||
## 0.2.5+2
|
||||
|
||||
- Cleaned up Serialization on extra_data
|
||||
|
||||
## 0.2.5+1
|
||||
|
||||
- Fix `channel.show` api call
|
||||
|
||||
## 0.2.5
|
||||
|
||||
- Add `channelType` and `channelId` properties to event object
|
||||
|
||||
## 0.2.4+2
|
||||
|
||||
- Fix query members messing channel state
|
||||
|
||||
## 0.2.4+1
|
||||
|
||||
- Do not resync if there is no channel in offlinestorage
|
||||
|
||||
## 0.2.4
|
||||
|
||||
- Add null-safety to ws disconnect
|
||||
- Add pagination parameters to queryUsers request
|
||||
|
||||
## 0.2.3+3
|
||||
|
||||
- Fix reaction add/remove logic
|
||||
|
||||
## 0.2.3+2
|
||||
|
||||
- Skip system messages during unreadCount computation
|
||||
|
||||
## 0.2.3+1
|
||||
|
||||
- Removed moor_ffi from dependencies in favor of moor/ffi
|
||||
|
||||
## 0.2.3
|
||||
|
||||
- Fix reject invite payload
|
||||
|
||||
- Add multi-tenant properties to channel and user
|
||||
|
||||
## 0.2.2+1
|
||||
|
||||
- Fix queryChannels payload
|
||||
|
||||
## 0.2.2
|
||||
|
||||
- Fix add/remove/invite members api calls
|
||||
|
||||
## 0.2.1
|
||||
|
||||
- Add `isMutedStream` to `Channel`
|
||||
- Add `isGroup` to `Channel`
|
||||
- Add `isDistinct` to `Channel`
|
||||
|
||||
## 0.2.0+2
|
||||
|
||||
- Fix search messages response class
|
||||
|
||||
## 0.2.0+1
|
||||
|
||||
- Fix offline members update
|
||||
- Add channel mutes
|
||||
- Fix default channel sort
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Add `lastMessage` getter to Channel.state
|
||||
- Add `isSystem` property to Message
|
||||
- Incremental websocket reconnection timeout
|
||||
- Add translate message api call
|
||||
- Add queryMembers api call
|
||||
- Add user list to client state
|
||||
- Synchronize channel members status
|
||||
- Add offline storage
|
||||
- Add push notifications helper functions
|
||||
|
||||
## 0.2.0-alpha+23
|
||||
|
||||
- Add `lastMessage` getter to `Channel.state`
|
||||
|
||||
## 0.2.0-alpha+22
|
||||
|
||||
- Add `isSystem` property to Message
|
||||
|
||||
## 0.2.0-alpha+21
|
||||
|
||||
- Incremental websocket reconnection timeout
|
||||
|
||||
## 0.2.0-alpha+20
|
||||
|
||||
- More robust offline storage insertions
|
||||
|
||||
## 0.2.0-alpha+19
|
||||
|
||||
- Add translate message api call
|
||||
- Add queryMembers api call
|
||||
|
||||
## 0.2.0-alpha+18
|
||||
|
||||
- Revert moor_ffi version to 0.5.0
|
||||
|
||||
## 0.2.0-alpha+17
|
||||
|
||||
- Add user list to client
|
||||
|
||||
- Synchronize channel members status
|
||||
|
||||
## 0.2.0-alpha+16
|
||||
|
||||
- Try QueryChannels when `resync` endpoint returns an error
|
||||
|
||||
## 0.2.0-alpha+15
|
||||
|
||||
- Fix receiving reactions
|
||||
|
||||
## 0.2.0-alpha+14
|
||||
|
||||
- Avoid sending local event for optimistic updates
|
||||
|
||||
## 0.2.0-alpha+13
|
||||
|
||||
- Fix offline on app first start up
|
||||
|
||||
## 0.2.0-alpha+12
|
||||
|
||||
- Fix retry mechanism in threads
|
||||
- Fix delete channel query
|
||||
|
||||
## 0.2.0-alpha+9
|
||||
|
||||
- Add retry mechanism and retry queue
|
||||
|
||||
## 0.2.0-alpha+8
|
||||
|
||||
- Add copyWith to Attachment
|
||||
|
||||
## 0.2.0-alpha+7
|
||||
|
||||
- Add channel deleted/updated event handling
|
||||
|
||||
## 0.2.0-alpha+6
|
||||
|
||||
- Align with stable release
|
||||
|
||||
## 0.2.0-alpha+5
|
||||
|
||||
- Rename client parameters
|
||||
|
||||
## 0.2.0-alpha+3
|
||||
|
||||
- Remove dependencies on notification service
|
||||
|
||||
- Expose some helping method for integrate offline storage with push notifications
|
||||
|
||||
## 0.2.0-alpha+2
|
||||
|
||||
- Fix unread count
|
||||
|
||||
## 0.2.0-alpha
|
||||
|
||||
- Offline storage
|
||||
|
||||
- Push notifications
|
||||
|
||||
- Minor bug fixes
|
||||
|
||||
## 0.1.30
|
||||
|
||||
- Add silent property to message
|
||||
|
||||
## 0.1.29
|
||||
|
||||
- Fix read event handling
|
||||
|
||||
## 0.1.28
|
||||
|
||||
- Fix bug clearing members when receiving a message
|
||||
|
||||
## 0.1.27
|
||||
|
||||
- Update dependencies
|
||||
|
||||
## 0.1.26
|
||||
|
||||
- Remove wrong `members` property from `ChannelModel`
|
||||
|
||||
## 0.1.25
|
||||
|
||||
- Fix online status
|
||||
|
||||
## 0.1.24
|
||||
|
||||
- Fix unread count
|
||||
|
||||
## 0.1.22
|
||||
|
||||
- Add mute/unmute channel
|
||||
|
||||
## 0.1.20
|
||||
|
||||
- Fix channel query path without id
|
||||
|
||||
## 0.1.19
|
||||
|
||||
- Fix loading message replies
|
||||
|
||||
## 0.1.18
|
||||
|
||||
- Export dio error
|
||||
|
||||
## 0.1.17
|
||||
|
||||
- Ignore current user typing events
|
||||
|
||||
- Add event types
|
||||
|
||||
## 0.1.16
|
||||
|
||||
- Fix message update
|
||||
|
||||
## 0.1.15
|
||||
|
||||
- Fix mentions handling
|
||||
|
||||
## 0.1.14
|
||||
|
||||
- Handle message modification and commands
|
||||
|
||||
## 0.1.13
|
||||
|
||||
- Add message.updated event handling
|
||||
|
||||
## 0.1.12
|
||||
|
||||
- Add export multipart_file from dio
|
||||
|
||||
## 0.1.11
|
||||
|
||||
- Add channel config checks
|
||||
|
||||
## 0.1.10
|
||||
|
||||
- Rename Channel.channelClients to channels
|
||||
|
||||
## 0.1.9
|
||||
|
||||
- Fix channel update on message delete
|
||||
|
||||
## 0.1.8
|
||||
|
||||
- Add delete message handling
|
||||
|
||||
## 0.1.7
|
||||
|
||||
- Add reaction handling
|
||||
|
||||
## 0.1.6
|
||||
|
||||
- Add initialized completer
|
||||
|
||||
- Update example
|
||||
|
||||
## 0.1.5
|
||||
|
||||
- Add `ClientState` and `ChannelClientState` classes to handle channel state updates using events
|
||||
|
||||
- Update example supporting threads
|
||||
|
||||
## 0.1.4
|
||||
|
||||
- Update some api with wrong or incomplete signatures
|
||||
|
||||
- Add documentation for public apis
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- add websocket reconnection logic
|
||||
|
||||
- add token expiration mechanism
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- add typing events handling
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- a better example can be found in the example/ directory
|
||||
|
||||
- fix some api calls and add missing one
|
||||
|
||||
## 0.0.2
|
||||
|
||||
- first beta version
|
||||
@@ -0,0 +1,219 @@
|
||||
SOURCE CODE LICENSE AGREEMENT
|
||||
|
||||
IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR
|
||||
ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT.
|
||||
|
||||
THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE
|
||||
BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE
|
||||
LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN
|
||||
INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN
|
||||
EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE
|
||||
OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN
|
||||
AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO
|
||||
THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND
|
||||
CUSTOMER TO THIS AGREEMENT.
|
||||
|
||||
STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING
|
||||
CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A
|
||||
COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS
|
||||
AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE
|
||||
USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU
|
||||
REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF
|
||||
STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE
|
||||
READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE
|
||||
BOUND BY ALL THE TERMS OF THIS AGREEMENT.
|
||||
|
||||
IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT,
|
||||
STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO
|
||||
NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND
|
||||
CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE
|
||||
SOFTWARE.
|
||||
|
||||
1. SOFTWARE. The Stream.io software accompanying this Agreement, may include
|
||||
Source Code, Executable Object Code, associated media, printed materials and
|
||||
documentation (collectively, the “Software”). The Software also includes any
|
||||
updates or upgrades to or new versions of the original Software, if and when
|
||||
made available to you by Stream.io. “Source Code” means computer programming
|
||||
code in human readable form that is not suitable for machine execution without
|
||||
the intervening steps of interpretation or compilation. “Executable Object
|
||||
Code" means the computer programming code in any other form than Source Code
|
||||
that is not readily perceivable by humans and suitable for machine execution
|
||||
without the intervening steps of interpretation or compilation. “Site” means a
|
||||
Customer location controlled by Customer. “Authorized User” means any employee
|
||||
or contractor of Customer working at the Site, who has signed a written
|
||||
confidentiality agreement with Customer or is otherwise bound in writing by
|
||||
confidentiality and use obligations at least as restrictive as those imposed
|
||||
under this Agreement.
|
||||
|
||||
2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in
|
||||
consideration for the representations, warranties, and covenants made by
|
||||
Customer in this Agreement, Stream.io grants to Customer, during the term of
|
||||
this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable
|
||||
license to:
|
||||
|
||||
a. install and use Software Source Code on password protected computers at a Site,
|
||||
restricted to Authorized Users;
|
||||
|
||||
b. create derivative works, improvements (whether or not patentable), extensions
|
||||
and other modifications to the Software Source Code (“Modifications”) to build
|
||||
unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s
|
||||
application program interface (“API”);
|
||||
|
||||
c. compile the Software Source Code to create Executable Object Code versions of
|
||||
the Software Source Code and Modifications to build such newsfeeds, activity
|
||||
streams, and in-app messaging via the API;
|
||||
|
||||
d. install, execute and use such Executable Object Code versions solely for
|
||||
Customer’s internal business use (including development of websites through
|
||||
which data generated by Stream services will be streamed (“Apps”));
|
||||
|
||||
e. use and distribute such Executable Object Code as part of Customer’s Apps; and
|
||||
|
||||
f. make electronic copies of the Software and Modifications as required for backup
|
||||
or archival purposes.
|
||||
|
||||
3. RESTRICTIONS. Customer is responsible for all activities that occur in
|
||||
connection with the Software. Customer will not, and will not attempt to: (a)
|
||||
sublicense or transfer the Software or any Source Code related to the Software
|
||||
or any of Customer’s rights under this Agreement, except as otherwise provided
|
||||
in this Agreement, (b) use the Software Source Code for the benefit of a third
|
||||
party or to operate a service; (c) allow any third party to access or use the
|
||||
Software Source Code; (d) sublicense or distribute the Software Source Code or
|
||||
any Modifications in Source Code or other derivative works based on any part of
|
||||
the Software Source Code; (e) use the Software in any manner that competes with
|
||||
Stream.io or its business; or (e) otherwise use the Software in any manner that
|
||||
exceeds the scope of use permitted in this Agreement. Customer shall use the
|
||||
Software in compliance with any accompanying documentation any laws applicable
|
||||
to Customer.
|
||||
|
||||
4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or
|
||||
software components that are open source in conjunction with the Software
|
||||
Source Code or any Modifications in Source Code or in any way that could
|
||||
subject the Software to any open source licenses.
|
||||
|
||||
5. CONTRACTORS. Under the rights granted to Customer under this Agreement,
|
||||
Customer may permit its employees, contractors, and agencies of Customer to
|
||||
become Authorized Users to exercise the rights to the Software granted to
|
||||
Customer in accordance with this Agreement solely on behalf of Customer to
|
||||
provide services to Customer; provided that Customer shall be liable for the
|
||||
acts and omissions of all Authorized Users to the extent any of such acts or
|
||||
omissions, if performed by Customer, would constitute a breach of, or otherwise
|
||||
give rise to liability to Customer under, this Agreement. Customer shall not
|
||||
and shall not permit any Authorized User to use the Software except as
|
||||
expressly permitted in this Agreement.
|
||||
|
||||
6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way
|
||||
to engage in the development of products or services which could be reasonably
|
||||
construed to provide a complete or partial functional or commercial alternative
|
||||
to Stream.io’s products or services (a “Competitive Product”). Customer shall
|
||||
ensure that there is no direct or indirect use of, or sharing of, Software
|
||||
source code, or other information based upon or derived from the Software to
|
||||
develop such products or services. Without derogating from the generality of
|
||||
the foregoing, development of Competitive Products shall include having direct
|
||||
or indirect access to, supervising, consulting or assisting in the development
|
||||
of, or producing any specifications, documentation, object code or source code
|
||||
for, all or part of a Competitive Product.
|
||||
|
||||
7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement,
|
||||
Modifications may only be created and used by Customer as permitted by this
|
||||
Agreement and Modification Source Code may not be distributed to third parties.
|
||||
Customer will not assert against Stream.io, its affiliates, or their customers,
|
||||
direct or indirect, agents and contractors, in any way, any patent rights that
|
||||
Customer may obtain relating to any Modifications for Stream.io, its
|
||||
affiliates’, or their customers’, direct or indirect, agents’ and contractors’
|
||||
manufacture, use, import, offer for sale or sale of any Stream.io products or
|
||||
services.
|
||||
|
||||
8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant
|
||||
to Stream.io standard download procedures. The Software is deemed accepted upon
|
||||
delivery.
|
||||
|
||||
9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to
|
||||
provide any support or consultation concerning the Software.
|
||||
|
||||
10. TERM AND TERMINATION. The term of this Agreement begins when the Software is
|
||||
downloaded or accessed and shall continue until terminated. Either party may
|
||||
terminate this Agreement upon written notice. This Agreement shall
|
||||
automatically terminate if Customer is or becomes a competitor of Stream.io or
|
||||
makes or sells any Competitive Products. Upon termination of this Agreement for
|
||||
any reason, (a) all rights granted to Customer in this Agreement immediately
|
||||
cease to exist, (b) Customer must promptly discontinue all use of the Software
|
||||
and return to Stream.io or destroy all copies of the Software in Customer’s
|
||||
possession or control. Any continued use of the Software by Customer or attempt
|
||||
by Customer to exercise any rights under this Agreement after this Agreement
|
||||
has terminated shall be considered copyright infringement and subject Customer
|
||||
to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9
|
||||
shall survive expiration or termination of this Agreement for any reason.
|
||||
|
||||
11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual
|
||||
property rights and proprietary rights relating thereto or embodied therein,
|
||||
are the exclusive property of Stream.io and its suppliers. Stream.io and its
|
||||
suppliers reserve all rights in and to the Software not expressly granted to
|
||||
Customer in this Agreement, and no other licenses or rights are granted by
|
||||
implication, estoppel or otherwise.
|
||||
|
||||
12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S
|
||||
OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND
|
||||
WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY
|
||||
KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT
|
||||
LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS,
|
||||
QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS
|
||||
ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED
|
||||
THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS
|
||||
SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO
|
||||
MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND
|
||||
DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW.
|
||||
CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE
|
||||
EXPRESS WARRANTIES IN THIS AGREEMENT.
|
||||
|
||||
13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S
|
||||
TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR
|
||||
THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE,
|
||||
SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT,
|
||||
CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND
|
||||
WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING
|
||||
TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON
|
||||
ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO
|
||||
THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY.
|
||||
|
||||
14. General. Customer may not assign or transfer this Agreement, by operation of
|
||||
law or otherwise, or any of its rights under this Agreement (including the
|
||||
license rights granted to Customer) to any third party without Stream.io’s
|
||||
prior written consent, which consent will not be unreasonably withheld or
|
||||
delayed. Stream.io may assign this Agreement, without consent, including, but
|
||||
limited to, affiliate or any successor to all or substantially all its business
|
||||
or assets to which this Agreement relates, whether by merger, sale of assets,
|
||||
sale of stock, reorganization or otherwise. Any attempted assignment or
|
||||
transfer in violation of the foregoing will be null and void. Stream.io shall
|
||||
not be liable hereunder by reason of any failure or delay in the performance of
|
||||
its obligations hereunder for any cause which is beyond the reasonable control.
|
||||
All notices, consents, and approvals under this Agreement must be delivered in
|
||||
writing by courier, by electronic mail, or by certified or registered mail,
|
||||
(postage prepaid and return receipt requested) to the other party at the
|
||||
address set forth in the customer agreement between Stream.io and Customer and
|
||||
will be effective upon receipt or when delivery is refused. This Agreement will
|
||||
be governed by and interpreted in accordance with the laws of the State of
|
||||
Colorado, without reference to its choice of laws rules. The United Nations
|
||||
Convention on Contracts for the International Sale of Goods does not apply to
|
||||
this Agreement. Any action or proceeding arising from or relating to this
|
||||
Agreement shall be brought in a federal or state court in Denver, Colorado, and
|
||||
each party irrevocably submits to the jurisdiction and venue of any such court
|
||||
in any such action or proceeding. All waivers must be in writing. Any waiver or
|
||||
failure to enforce any provision of this Agreement on one occasion will not be
|
||||
deemed a waiver of any other provision or of such provision on any other
|
||||
occasion. If any provision of this Agreement is unenforceable, such provision
|
||||
will be changed and interpreted to accomplish the objectives of such provision
|
||||
to the greatest extent possible under applicable law and the remaining
|
||||
provisions will continue in full force and effect. Customer shall not violate
|
||||
any applicable law, rule or regulation, including those regarding the export of
|
||||
technical data. The headings of Sections of this Agreement are for convenience
|
||||
and are not to be used in interpreting this Agreement. As used in this
|
||||
Agreement, the word “including” means “including but not limited to.” This
|
||||
Agreement (including all exhibits and attachments) constitutes the entire
|
||||
agreement between the parties regarding the subject hereof and supersedes all
|
||||
prior or contemporaneous agreements, understandings and communication, whether
|
||||
written or oral. This Agreement may be amended only by a written document
|
||||
signed by both parties. The terms of any purchase order or similar document
|
||||
submitted by Customer to Stream.io will have no effect.
|
||||
@@ -0,0 +1,114 @@
|
||||
# Stream Chat Dart
|
||||
[](https://pub.dartlang.org/packages/stream_chat)
|
||||

|
||||

|
||||
[](https://codecov.io/gh/GetStream/stream-chat-dart)
|
||||
|
||||
stream-chat-dart is the official Dart client for Stream Chat, a service for building chat applications. This library can be used on any Dart project and on both mobile and web apps with Flutter.
|
||||
|
||||
You can sign up for a Stream account at https://getstream.io/chat/
|
||||
|
||||
## Getting started
|
||||
|
||||
### Add dependency
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
stream_chat: ^1.0.0-beta
|
||||
```
|
||||
|
||||
You should then run `flutter packages get`
|
||||
|
||||
## Example Project
|
||||
|
||||
There is a detailed Flutter example project in the `example` folder. You can directly run and play on it.
|
||||
|
||||
## Setup API Client
|
||||
|
||||
First you need to instantiate a chat client. The Chat client will manage API call, event handling and manage the websocket connection to Stream Chat servers. You should only create the client once and re-use it across your application.
|
||||
|
||||
```dart
|
||||
final client = StreamChatClient("stream-chat-api-key");
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
By default the Chat Client will write all messages with level Warn or Error to stdout.
|
||||
|
||||
#### Change Logging Level
|
||||
|
||||
During development you might want to enable more logging information, you can change the default log level when constructing the client.
|
||||
|
||||
```dart
|
||||
final client = StreamChatClient("stream-chat-api-key", logLevel: Level.INFO);
|
||||
```
|
||||
|
||||
#### Custom Logger
|
||||
|
||||
You can handle the log messages directly instead of have them written to stdout, this is very convenient if you use an error tracking tool or if you want to centralize your logs into one facility.
|
||||
|
||||
```dart
|
||||
myLogHandlerFunction = (LogRecord record) {
|
||||
// do something with the record (ie. send it to Sentry or Fabric)
|
||||
}
|
||||
|
||||
final client = StreamChatClient("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction);
|
||||
```
|
||||
|
||||
### Offline storage
|
||||
|
||||
To add data persistance you can extend the class `ChatPersistenceClient` and pass an instance to the `StreamChatClient`.
|
||||
|
||||
```dart
|
||||
class CustomChatPersistentClient extends ChatPersistenceClient {
|
||||
...
|
||||
}
|
||||
|
||||
final client = StreamChatClient(
|
||||
apiKey ?? kDefaultStreamApiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = CustomChatPersistentClient();
|
||||
```
|
||||
|
||||
We provide an official persistent client in the (stream_chat_persistence)[https://pub.dev/packages/stream_chat_persistence] package.
|
||||
|
||||
```dart
|
||||
import 'package:stream_chat_persistence/stream_chat_persistence.dart';
|
||||
|
||||
final chatPersistentClient = StreamChatPersistenceClient(
|
||||
logLevel: Level.INFO,
|
||||
connectionMode: ConnectionMode.background,
|
||||
);
|
||||
|
||||
final client = StreamChatClient(
|
||||
apiKey ?? kDefaultStreamApiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = chatPersistentClient;
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
### Code conventions
|
||||
|
||||
- Make sure that you run `dartfmt` before commiting your code
|
||||
- Make sure all public methods and functions are well documented
|
||||
|
||||
### Running tests
|
||||
|
||||
- run `flutter test`
|
||||
|
||||
### Releasing a new version
|
||||
|
||||
- update the package version on `pubspec.yaml` and `version.dart`
|
||||
|
||||
- add a changelog entry on `CHANGELOG.md`
|
||||
|
||||
- run `flutter pub publish` to publish the package
|
||||
|
||||
### Watch models and generate JSON code
|
||||
|
||||
JSON serialization relies on code generation; make sure to keep that running while you make changes to the library
|
||||
|
||||
```bash
|
||||
flutter pub run build_runner watch
|
||||
```
|
||||
@@ -0,0 +1,62 @@
|
||||
include: package:pedantic/analysis_options.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- lib/**/*.g.dart
|
||||
- example/*
|
||||
- test/*
|
||||
|
||||
linter:
|
||||
rules:
|
||||
# these rules are documented on and in the same order as
|
||||
# the Dart Lint rules page to make maintenance easier
|
||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||
# - always_declare_return_types
|
||||
# - always_specify_types
|
||||
# - annotate_overrides
|
||||
# - avoid_as
|
||||
- avoid_empty_else
|
||||
- avoid_init_to_null
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_web_libraries_in_flutter
|
||||
- await_only_futures
|
||||
- camel_case_types
|
||||
- cancel_subscriptions
|
||||
- close_sinks
|
||||
# - comment_references # we do not presume as to what people want to reference in their dartdocs
|
||||
# - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
|
||||
- control_flow_in_finally
|
||||
- empty_constructor_bodies
|
||||
- empty_statements
|
||||
- hash_and_equals
|
||||
- implementation_imports
|
||||
# - invariant_booleans
|
||||
# - iterable_contains_unrelated_type
|
||||
- library_names
|
||||
# - library_prefixes
|
||||
# - list_remove_unrelated_type
|
||||
# - literal_only_boolean_expressions
|
||||
- non_constant_identifier_names
|
||||
# - one_member_abstracts
|
||||
# - only_throw_errors
|
||||
# - overridden_fields
|
||||
- package_api_docs
|
||||
- package_names
|
||||
- package_prefixed_library_names
|
||||
- prefer_is_not_empty
|
||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||
- public_member_api_docs
|
||||
- slash_for_doc_comments
|
||||
# - sort_constructors_first
|
||||
# - sort_unnamed_constructors_first
|
||||
# - super_goes_last # no longer needed w/ Dart 2
|
||||
- test_types_in_equals
|
||||
- throw_in_finally
|
||||
# - type_annotate_public_apis # subset of always_specify_types
|
||||
- type_init_formals
|
||||
# - unawaited_futures
|
||||
- unnecessary_brace_in_string_interps
|
||||
- unnecessary_getters_setters
|
||||
- unnecessary_statements
|
||||
- unrelated_type_equality_checks
|
||||
- valid_regexps
|
||||
@@ -0,0 +1,8 @@
|
||||
targets:
|
||||
$default:
|
||||
builders:
|
||||
json_serializable:
|
||||
options:
|
||||
explicit_to_json: true
|
||||
field_rename: snake
|
||||
any_map: true
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
@@ -33,7 +34,8 @@
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Exceptions to above rules.
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
fvm
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
@@ -4,7 +4,7 @@
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
|
||||
revision: 78910062997c3a836feee883712c241a5fd22983
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
@@ -0,0 +1,2 @@
|
||||
# Stream Chat Dart Example
|
||||
Please see `lib/` for example code.
|
||||
@@ -0,0 +1,11 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
key.properties
|
||||
@@ -0,0 +1,63 @@
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.example"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.example">
|
||||
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||
In most cases you can leave this as-is, but you if you want to provide
|
||||
additional functionality it is fine to subclass or reimplement
|
||||
FlutterApplication and put your custom class here. -->
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:label="example"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<!-- Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.example.example
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
}
|
||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 721 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@android:color/white</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -6,9 +6,8 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.enableR8=true
|
||||
@@ -1,4 +1,4 @@
|
||||
#Thu Oct 22 11:03:39 CEST 2020
|
||||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
@@ -0,0 +1,11 @@
|
||||
include ':app'
|
||||
|
||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
def properties = new Properties()
|
||||
|
||||
assert localPropertiesFile.exists()
|
||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
||||
@@ -4,7 +4,4 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,13 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |