diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..90ef515 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: plugfox +#open_collective: # Replace with a single Open Collective username +#ko_fi: # Replace with a single Ko-fi username +#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +#liberapay: # Replace with a single Liberapay username +#issuehunt: # Replace with a single IssueHunt username +#otechie: # Replace with a single Otechie username +#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: ['https://www.buymeacoffee.com/plugfox', 'https://boosty.to/plugfox'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..9b77ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "" +labels: "" +assignees: "" +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] + +**Smartphone (please complete the following information):** + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..c2b01f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & Help + url: https://t.me/ru_dart + about: Ask a question about Spinify \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..2bc5d5f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: "" +assignees: "" +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml new file mode 100644 index 0000000..7b9150f --- /dev/null +++ b/.github/actions/setup/action.yaml @@ -0,0 +1,65 @@ +name: Setup +description: Sets up the Flutter environment + +inputs: + flutter-version: + description: 'The version of Flutter to use' + required: false + default: '3.24.5' + pub-cache: + description: 'The name of the pub cache variable' + required: false + default: app + +runs: + using: composite + steps: + - name: πŸ“¦ Checkout the repo + uses: actions/checkout@v4 + + - name: πŸ”’ Set up version from tags + id: set-version + if: startsWith(github.ref, 'refs/tags') + shell: bash + run: | + BASE_VERSION="${GITHUB_REF#refs/tags/v}" + UNIXTIME=$(date +%s) + VERSION="${BASE_VERSION}+${UNIXTIME}" + echo "VERSION=$VERSION" >> $GITHUB_ENV + sed -i "s/^version: .*/version: ${VERSION}/" pubspec.yaml + echo "Version set to $VERSION" + + - name: πŸš‚ Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: "stable" + flutter-version: '${{ inputs.flutter-version }}' + + - name: πŸ“€ Restore Pub modules + id: cache-pub-restore + uses: actions/cache/restore@v4 + with: + path: | + /home/runner/.pub-cache + key: ${{ runner.os }}-pub-${{ inputs.pub-cache }}-${{ hashFiles('pubspec.lock') }} + + - name: πŸ‘· Install Dependencies + shell: bash + run: | + echo /home/runner/.pub-cache/bin >> $GITHUB_PATH + flutter config --no-cli-animations --no-analytics + flutter pub get + + #- name: ⏲️ Run build runner + # shell: bash + # run: | + # dart run build_runner build --delete-conflicting-outputs --release + + - name: πŸ“₯ Save Pub modules + id: cache-pub-save + if: steps.cache-pub-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: | + /home/runner/.pub-cache + key: ${{ steps.cache-pub-restore.outputs.cache-primary-key }} diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..e54675c --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,10 @@ +version: 2 +enable-beta-ecosystems: true +updates: + - directory: "/" + open-pull-requests-limit: 5 + package-ecosystem: "pub" + rebase-strategy: auto + schedule: + interval: "monthly" + timezone: "Etc/GMT" diff --git a/.github/workflows/checkout.yml b/.github/workflows/checkout.yml new file mode 100644 index 0000000..e646263 --- /dev/null +++ b/.github/workflows/checkout.yml @@ -0,0 +1,116 @@ +name: Checkout + +on: + workflow_dispatch: + push: + branches: + - "main" + - "master" + #- "dev" + #- "develop" + #- "feature/**" + #- "bugfix/**" + #- "hotfix/**" + #- "support/**" + # paths: + # - "pubspec.yaml" + # - "pubspec.lock" + # - ".github/**.yaml" + # - ".github/**.yml" + # - "lib/**.dart" + # - "test/**.dart" + # - "packages/**" + # - "example/**.dart" + pull_request: + branches: + - "main" + - "master" + - "dev" + - "develop" + - "feature/**" + - "bugfix/**" + - "hotfix/**" + - "support/**" + paths: + - "pubspec.yaml" + - ".github/**.yaml" + - ".github/**.yml" + - "lib/**.dart" + - "test/**.dart" + - "example/**.dart" + +permissions: + contents: read + actions: read + checks: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + checkout: + name: "πŸ§ͺ Check code with analysis, format, and tests" + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./ + timeout-minutes: 10 + steps: + - name: πŸ“¦ Get the .github actions + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + + - name: πŸš‚ Setup Flutter and dependencies + uses: ./.github/actions/setup + with: + flutter-version: 3.24.3 + + - name: πŸ‘· Install Dependencies + timeout-minutes: 1 + run: | + flutter pub get + + - name: 🚦 Check code format + id: check-format + timeout-minutes: 1 + run: | + find lib test -name "*.dart" ! -name "*.*.dart" -print0 | xargs -0 dart format --set-exit-if-changed --line-length 80 -o none lib/ test/ + + - name: πŸ“ˆ Check analyzer + id: check-analyzer + timeout-minutes: 1 + run: flutter analyze --fatal-infos --fatal-warnings lib/ test/ + + - name: πŸ‘€ Verify versions + id: verify-versions + timeout-minutes: 1 + run: | + test -f pubspec.yaml && test -f CHANGELOG.md + version_pubspec=$(grep '^version:' pubspec.yaml | awk '{print $2}' | sed 's/[^[:print:]]//g') + test -n "$version_pubspec" + echo "Version from pubspec.yaml: '$version_pubspec'" + echo "$version_pubspec" > /tmp/version_pubspec + grep -q "# $version_pubspec" CHANGELOG.md || (echo "Version not found in CHANGELOG.md" >&2; exit 1) + + - name: πŸ§ͺ Unit & Widget tests + timeout-minutes: 20 + run: | + flutter test --coverage --concurrency=40 test/unit_test.dart test/widget_test.dart + + #- name: πŸ“₯ Upload coverage report + # timeout-minutes: 5 + # if: ${{ github.actor != 'dependabot[bot]' }} + # uses: codecov/codecov-action@v2 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # files: ./coverage/lcov.info + + - name: πŸ“₯ Upload test report + uses: actions/upload-artifact@v4 + if: (success() || failure()) && ${{ github.actor != 'dependabot[bot]' }} + with: + name: test-results + path: reports/tests.json diff --git a/.github/workflows/test-report.yml b/.github/workflows/test-report.yml new file mode 100644 index 0000000..6fe454d --- /dev/null +++ b/.github/workflows/test-report.yml @@ -0,0 +1,27 @@ +name: "Test Report" + +on: + workflow_run: + workflows: ["Checkout"] # runs after "Checkout" workflow + types: + - completed + +permissions: + contents: read + actions: read + checks: write + +jobs: + report: + name: "πŸš› Test report" + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Test report + uses: dorny/test-reporter@v1 + with: + artifact: test-results + name: Test Report + path: "**/tests.json" + reporter: flutter-json + fail-on-error: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3125e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,87 @@ +# Don’t commit the following directories created by pub. +.buildlog +.dart_tool/ +.pub/ +build/ +packages +*.packages +.idea/ +doc + +# Or the files created by dart2js. +*.dart.js +*.js_ +*.js.deps +*.js.map + +# Include when developing application packages. +pubspec.lock +coverage* + +# Codegen +*.g.dart +!pubspec.yaml.g.dart + +# Logs +l/ + +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws + +# 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/ +**/ios/Flutter/.last_build_id +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +# Pana +log.pana.json + +# Test +coverage/ +.coverage/ +/test/**/*.json +/test/.test_coverage.dart +reports/ +.reports/ + +# Binaries for programs and plugins +*.exe +*.exe~ + +pubspec.lock \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..7025a64 --- /dev/null +++ b/.metadata @@ -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: "dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668" + channel: "stable" + +project_type: package diff --git a/.pubignore b/.pubignore new file mode 100644 index 0000000..34c62e3 --- /dev/null +++ b/.pubignore @@ -0,0 +1 @@ +pubspec.lock \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..767a67f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "dart-code.dart-code", + "Dart-Code.flutter", + "github.vscode-github-actions", + "raczzalan.webgl-glsl-editor", + "circledev.glsl-canvas" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..34a8c7e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Example (Debug)", + "type": "dart", + "program": "lib/main.dart", + "request": "launch", + "flutterMode": "debug", + "cwd": "${workspaceFolder}/example", + "args": [ + "--dart-define-from-file=config/development.json", + ], + "env": {} + }, + { + "name": "Example (Release)", + "type": "dart", + "program": "lib/main.dart", + "request": "launch", + "flutterMode": "release", + "cwd": "${workspaceFolder}/example", + "args": [ + "--dart-define-from-file=config/development.json", + ], + "env": {} + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d7b3b3e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,98 @@ +{ + "[dart]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.suggest.snippetsPreventQuickSuggestions": false, + "editor.suggestSelection": "first", + "editor.tabCompletion": "onlySnippets", + "editor.wordBasedSuggestions": "off", + "editor.selectionHighlight": false, + "editor.defaultFormatter": "Dart-Code.dart-code", + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.formatOnPaste": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.quickSuggestions": { + "comments": "on", + "strings": "on", + "other": "on" + }, + "editor.links": true, + "editor.rulers": [ + 80 + ] + }, + "dart.lineLength": 80, + "dart.doNotFormat": [ + "**.g.dart", + "**.gql.dart", + "**.freezed.dart", + "**.config.dart", + "**.mocks.dart", + "**.gen.dart", + "**.pb.dart", + "**.pbenum.dart", + "**.pbjson.dart", + "**/generated/**" + ], + // Flutter Version Manager + //"dart.flutterSdkPath": ".fvm/flutter_sdk", + // Remove .fvm files from search + "search.exclude": { + //"**/.fvm": true, + ".dart_tool": true, + "coverage": true, + "build": true + }, + // Remove from file watching + "files.watcherExclude": { + //"**/.fvm": true, + ".dart_tool": true, + "coverage": true, + "build": true + }, + // Causes the debug view to automatically appear when a breakpoint is hit. This + // setting is global and not configurable per-language. + "debug.openDebug": "openOnDebugBreak", + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.expand": false, + "explorer.fileNesting.patterns": { + "pubspec.yaml": ".flutter-plugins, .packages, .dart_tool, .flutter-plugins-dependencies, .metadata, .packages, pubspec.lock, build.yaml, analysis_options.yaml, all_lint_rules.yaml, dart*.yaml, flutter*.yaml, icons_launcher.yaml", + ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*", + "readme.*": "authors, backers.md, changelog*, citation*, code_of_conduct.md, codeowners, contributing.md, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors.md", + "*.dart": "$(capture).g.dart, $(capture).freezed.dart, $(capture).config.dart" + }, + /* "files.associations": { + "*.drift": "sql" + }, */ + /* "highlight.regexes": { + "(\"@\\s*.+\":\\s{0,1}{},)": { + "filterFileRegex": ".*\\.arb", + "decorations": [ + { + "overviewRulerColor": "#d19a66", + "backgroundColor": "#d19a66", + "color": "#282c34", + "fontWeight": "bold" + } + ] + } + }, */ + // -- Shaders -- // + "glsl-canvas.refreshOnChange": false, + "glsl-canvas.refreshOnSave": true, + "[glsl]": { + "editor.defaultFormatter": "raczzalan.webgl-glsl-editor" + }, + "[frag]": { + "editor.defaultFormatter": "raczzalan.webgl-glsl-editor" + }, + "[vert]": { + "editor.defaultFormatter": "raczzalan.webgl-glsl-editor" + }, + "editor.defaultFormatter": "raczzalan.webgl-glsl-editor", + "notebook.defaultFormatter": "raczzalan.webgl-glsl-editor", +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..075d269 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,470 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "dart:pub:get", + "detail": "Get dependencies for the project", + "icon": { + "color": "terminal.ansiGreen", + "id": "cloud-download" + }, + "dependsOn": [], + "type": "shell", + "command": "dart pub get", + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:get-protoc-plugin", + "detail": "Get protoc plugin", + "icon": { + "color": "terminal.ansiGreen", + "id": "cloud-download" + }, + "type": "shell", + "command": "dart pub global activate protoc_plugin", + "dependsOn": [], + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:generate-protobuf", + "detail": "Generate protobuf files", + "icon": { + "color": "terminal.ansiGreen", + "id": "code" + }, + "type": "shell", + "command": [ + "protoc", + "--proto_path=lib/src/transport/protobuf", + "--dart_out=lib/src/transport/protobuf lib/src/transport/protobuf/client.proto" + ], + "dependsOn": [ + "dart:get-protoc-plugin" + ], + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:build_runner:all", + "detail": "Generate code for the project", + "icon": { + "color": "terminal.ansiGreen", + "id": "code" + }, + "type": "shell", + "command": [ + "dart run build_runner build --delete-conflicting-outputs", + "&& dart format --fix -l 80 lib test tool example" + ], + "dependsOn": [ + "dart:dependencies", + "dart:generate-protobuf" + ], + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:build_runner:dir", + "detail": "Generate code for the directory", + "type": "shell", + "icon": { + "color": "terminal.ansiGreen", + "id": "code" + }, + "command": [ + "dart run build_runner build --build-filter '${fileDirname}/*.dart'", + "&& dart format --fix -l 80 '${fileDirname}'" + ], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "dependsOn": [ + "dart:pub:get" + ], + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:build_runner:watch", + "detail": "Watch for changes in the project", + "type": "shell", + "icon": { + "color": "terminal.ansiGreen", + "id": "code" + }, + "command": "dart run build_runner watch --build-filter \"${input:directory}/**/*.dart\"", + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "dependsOn": [ + "dart:pub:get" + ], + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "dart:format", + "detail": "Format all files in the project", + "icon": { + "color": "terminal.ansiGreen", + "id": "lightbulb-autofix" + }, + "type": "shell", + "command": [ + "dart format --fix -l 80 lib test tool example" + ], + "dependsOn": [], + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "dart" + } + }, + { + "label": "centrifugo:start", + "detail": "Start centrifugo server", + "icon": { + "color": "terminal.ansiBlue", + "id": "server" + }, + "type": "shell", + "windows": { + "command": "docker", + "args": [ + "run", + "-d", + "--rm", + "--ulimit=nofile=65536:65536", + "-p=8000:8000/tcp", + "--volume=${PWD}/config.json:/centrifugo/config.json:ro", + "--name=centrifugo", + "centrifugo/centrifugo:latest", + "centrifugo", + "--client_insecure", + "--admin", + "--admin_insecure", + "--log_level=debug" + ] + }, + "linux": { + "command": "docker", + "args": [ + "run", + "-d", + "--rm", + "--ulimit=nofile=65536:65536", + "-p=8000:8000/tcp", + "--volume=${PWD}/config.json:/centrifugo/config.json:ro", + "--name=centrifugo", + "centrifugo/centrifugo:latest", + "centrifugo", + //"--client_insecure", + "--admin", + "--admin_insecure", + "--log_level=debug" + ] + }, + "osx": { + "command": "docker", + "args": [ + "run", + "-d", + "--rm", + "--ulimit=nofile=65536:65536", + "-p=8000:8000/tcp", + "--volume=${PWD}/config.json:/centrifugo/config.json:ro", + "--name=centrifugo", + "centrifugo/centrifugo:latest", + "centrifugo", + "--client_insecure", + "--admin", + "--admin_insecure", + "--log_level=debug" + ] + }, + "dependsOn": [], + "args": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "centrifugo" + } + }, + { + "label": "centrifugo:stop", + "detail": "Stop centrifugo server", + "icon": { + "color": "terminal.ansiRed", + "id": "server" + }, + "type": "shell", + "command": "docker", + "args": [ + "stop", + "centrifugo" + ], + "dependsOn": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "centrifugo" + } + }, + { + "label": "centrifugo:gentoken", + "detail": "Generate new user token for centrifugo server", + "icon": { + "color": "terminal.ansiCyan", + "id": "key" + }, + "type": "shell", + "command": "docker", + "args": [ + "run", + "-it", + "--rm", + "--volume=${PWD}/config.json:/centrifugo/config.json:ro", + "--name=centrifugo-cli", + "centrifugo/centrifugo:latest", + "centrifugo", + "gentoken", + "--user=dart", + "--ttl=604800" + ], + "dependsOn": [], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "centrifugo" + } + }, + { + "label": "echo:start", + "detail": "Start echo server", + "icon": { + "color": "terminal.ansiBlue", + "id": "server" + }, + "type": "shell", + "command": "dart", + "isBackground": false, + "options": { + "cwd": "${workspaceFolder}/tool", + "env": {} + }, + "args": [ + "run", + "echo_up.dart" + ], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "centrifugo" + } + }, + { + "label": "echo:stop", + "detail": "Stop echo server", + "icon": { + "color": "terminal.ansiRed", + "id": "server" + }, + "type": "shell", + "command": "dart", + "options": { + "cwd": "${workspaceFolder}/tool", + }, + "dependsOn": [], + "args": [ + "run", + "echo_down.dart" + ], + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": false, + "presentation": { + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false, + "group": "echo" + } + }, + { + "label": "echo:run", + "detail": "Run echo server with Go", + "icon": { + "color": "terminal.ansiGreen", + "id": "server" + }, + "options": { + "cwd": "${workspaceFolder}/tool/echo", + "env": {} + }, + "type": "shell", + "command": "go", + "args": [ + "run", + "echo.go" + ], + "isBackground": true, + "group": { + "kind": "none", + "isDefault": true + }, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "dedicated", + "focus": true, + "clear": true, + "group": "echo" + } + }, + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..acb2741 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +- Basic functionality diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..393e439 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Matiunin Mikhail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..766340a --- /dev/null +++ b/Makefile @@ -0,0 +1,96 @@ +SHELL :=/bin/bash -e -o pipefail +PWD :=$(shell pwd) + +.DEFAULT_GOAL := all +.PHONY: all +all: ## build pipeline +all: format check test + +.PHONY: ci +ci: ## CI build pipeline +ci: all + +.PHONY: precommit +precommit: ## validate the branch before commit +precommit: all + +.PHONY: help +help: + @echo 'Usage: make ... ' + @echo '' + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: format +format: ## Format the code + @dart format -l 80 --fix lib/ test/ + @dart fix --apply . + +.PHONY: get +get: ## Get the dependencies + @flutter pub get + +.PHONY: outdated +outdated: get ## Check for outdated dependencies + @flutter pub outdated --show-all --dev-dependencies --dependency-overrides --transitive --no-prereleases + +.PHONY: test +test: get ## Run the tests + @flutter test --concurrency=40 test/unit_test.dart test/widget_test.dart + +.PHONY: publish-check +publish-check: ## Check the package before publishing + @flutter pub publish --dry-run + +.PHONY: deploy-check +deploy-check: publish-check + +.PHONY: publish +publish: ## Publish the package + @flutter pub publish + +.PHONY: deploy +deploy: publish + +.PHONY: coverage +coverage: get ## Generate the coverage report + @flutter test --coverage --concurrency=40 test/unit_test.dart test/widget_test.dart +# @lcov --remove coverage/lcov.info 'lib/**/*.g.dart' -o coverage/lcov.info + @lcov --list coverage/lcov.info + @genhtml -o coverage coverage/lcov.info + +.PHONY: analyze +analyze: get ## Analyze the code + @dart format --set-exit-if-changed -l 80 -o none lib/ test/ + @flutter analyze --fatal-infos --fatal-warnings lib/ test/ + +.PHONY: check +check: analyze publish-check ## Check the code + @dart pub global activate pana + @pana --json --no-warning --line-length 80 > log.pana.json + +.PHONY: pana +pana: check + +#.PHONY: generate +#generate: get ## Generate the code +# @dart pub global activate protoc_plugin +# @protoc --proto_path=lib/src/protobuf --dart_out=lib/src/protobuf lib/src/protobuf/client.proto +# @dart run build_runner build --delete-conflicting-outputs +# @dart format -l 80 lib/src/model/pubspec.yaml.g.dart lib/src/protobuf/ test/ + +#.PHONY: gen +#gen: generate + +#.PHONY: codegen +#codegen: generate + +.PHONY: version +version: ## Show the Flutter version + @flutter --version + @which flutter + +.PHONY: diff +diff: ## git diff + $(call print-target) + @git diff --exit-code + @RES=$$(git status --porcelain) ; if [ -n "$$RES" ]; then echo $$RES && exit 1 ; fi diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a35f5dd --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,209 @@ +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: + # Build + - "build/**" + # Codegen + - "lib/**.g.dart" + # Tests + - "test/**.mocks.dart" + - ".test_coverage.dart" + # Assets + - "assets/**" + + # Enable the following options to enable strong mode. + language: + strict-casts: true + strict-raw-types: true + strict-inference: true + + errors: + # Allow having TODOs in the code + todo: ignore + + # Info + directives_ordering: info + always_declare_return_types: info + + # Warning + unsafe_html: warning + missing_return: warning + missing_required_param: warning + no_logic_in_create_state: warning + empty_catches: warning + + # Error + prefer_relative_imports: error + avoid_relative_lib_imports: error + avoid_slow_async_io: error + avoid_types_as_parameter_names: error + valid_regexps: error + always_require_non_null_named_parameters: error + +linter: + rules: + # Public packages + public_member_api_docs: true + lines_longer_than_80_chars: true + + # Enabling rules + prefer_relative_imports: true + avoid_relative_lib_imports: true + + # Disable rules + sort_pub_dependencies: false + always_use_package_imports: false + prefer_final_locals: false + avoid_escaping_inner_quotes: false + curly_braces_in_flow_control_structures: false + + # Enabled + use_named_constants: true + unnecessary_constructor_name: true + sort_constructors_first: true + exhaustive_cases: true + sort_unnamed_constructors_first: true + type_literal_in_constant_pattern: true + always_put_required_named_parameters_first: true + avoid_annotating_with_dynamic: true + avoid_bool_literals_in_conditional_expressions: true + avoid_double_and_int_checks: true + avoid_field_initializers_in_const_classes: true + avoid_implementing_value_types: true + avoid_js_rounded_ints: true + avoid_print: true + avoid_renaming_method_parameters: true + avoid_returning_null_for_void: true + avoid_single_cascade_in_expression_statements: true + avoid_slow_async_io: true + avoid_unnecessary_containers: true + avoid_unused_constructor_parameters: true + avoid_void_async: true + await_only_futures: true + cancel_subscriptions: true + cascade_invocations: true + close_sinks: true + control_flow_in_finally: true + empty_statements: true + collection_methods_unrelated_type: true + join_return_with_assignment: true + leading_newlines_in_multiline_strings: true + literal_only_boolean_expressions: true + missing_whitespace_between_adjacent_strings: true + no_adjacent_strings_in_list: true + no_logic_in_create_state: true + no_runtimeType_toString: true + only_throw_errors: true + overridden_fields: true + package_names: true + package_prefixed_library_names: true + parameter_assignments: true + prefer_asserts_in_initializer_lists: true + prefer_asserts_with_message: true + prefer_const_constructors: true + prefer_const_constructors_in_immutables: true + prefer_const_declarations: true + prefer_const_literals_to_create_immutables: true + prefer_constructors_over_static_methods: true + prefer_expression_function_bodies: true + prefer_final_in_for_each: true + prefer_foreach: true + prefer_if_elements_to_conditional_expressions: true + prefer_inlined_adds: true + prefer_int_literals: true + prefer_is_not_operator: true + prefer_null_aware_operators: true + prefer_typing_uninitialized_variables: true + prefer_void_to_null: true + provide_deprecation_message: true + sized_box_for_whitespace: true + sort_child_properties_last: true + test_types_in_equals: true + throw_in_finally: true + unnecessary_null_aware_assignments: true + unnecessary_overrides: true + unnecessary_parenthesis: true + unnecessary_raw_strings: true + unnecessary_statements: true + unnecessary_string_escapes: true + unnecessary_string_interpolations: true + unsafe_html: true + use_full_hex_values_for_flutter_colors: true + use_raw_strings: true + use_string_buffers: true + valid_regexps: true + void_checks: true + + # Pedantic 1.9.0 + always_declare_return_types: true + annotate_overrides: true + avoid_empty_else: true + avoid_init_to_null: true + avoid_null_checks_in_equality_operators: true + avoid_return_types_on_setters: true + avoid_shadowing_type_parameters: true + avoid_types_as_parameter_names: true + camel_case_extensions: true + empty_catches: true + empty_constructor_bodies: true + library_names: true + library_prefixes: true + no_duplicate_case_values: true + null_closures: true + omit_local_variable_types: true + prefer_adjacent_string_concatenation: true + prefer_collection_literals: true + prefer_conditional_assignment: true + prefer_contains: true + prefer_final_fields: true + prefer_for_elements_to_map_fromIterable: true + prefer_generic_function_type_aliases: true + prefer_if_null_operators: true + prefer_is_empty: true + prefer_is_not_empty: true + prefer_iterable_whereType: true + prefer_single_quotes: true + prefer_spread_collections: true + recursive_getters: true + slash_for_doc_comments: true + type_init_formals: true + unawaited_futures: true + unnecessary_const: true + unnecessary_new: true + unnecessary_null_in_if_null_operators: true + unnecessary_this: true + unrelated_type_equality_checks: true + use_function_type_syntax_for_parameters: true + use_rethrow_when_possible: true + + # Effective_dart 1.2.0 + camel_case_types: true + file_names: true + non_constant_identifier_names: true + constant_identifier_names: true + directives_ordering: true + package_api_docs: true + implementation_imports: true + prefer_interpolation_to_compose_strings: true + unnecessary_brace_in_string_interps: true + avoid_function_literals_in_foreach_calls: true + prefer_function_declarations_over_variables: true + unnecessary_lambdas: true + unnecessary_getters_setters: true + prefer_initializing_formals: true + avoid_catches_without_on_clauses: true + avoid_catching_errors: true + use_to_and_as_if_applicable: true + one_member_abstracts: true + avoid_classes_with_only_static_members: true + prefer_mixin: true + use_setters_to_change_properties: true + avoid_setters_without_getters: true + avoid_returning_this: true + type_annotate_public_apis: true + avoid_types_on_closure_parameters: true + avoid_private_typedef_functions: true + avoid_positional_boolean_parameters: true + hash_and_equals: true + avoid_equals_and_hash_code_on_mutable_classes: true diff --git a/dart_test.yaml b/dart_test.yaml new file mode 100644 index 0000000..d14b29c --- /dev/null +++ b/dart_test.yaml @@ -0,0 +1,13 @@ +timeout: 1x + +platforms: + - vm + +file_reporters: + json: reports/tests.json + +tags: + unit: + timeout: 1x + smoke: + timeout: 2x diff --git a/lib/mess.dart b/lib/mess.dart new file mode 100644 index 0000000..316a905 --- /dev/null +++ b/lib/mess.dart @@ -0,0 +1 @@ +library; diff --git a/lib/src/.keep b/lib/src/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..9f27356 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,56 @@ +name: mess +description: > + **Mass Entity State System (MESS)** is a robust ECS (Entity-Component-System) library for Flutter + designed to manage large-scale entities and their states. + MESS enables developers to build complex systems with a clear architecture, ensuring high performance and scalability. + +version: 0.0.1 + +homepage: https://github.com/PlugFox/mess + +repository: https://github.com/PlugFox/mess + +issue_tracker: https://github.com/PlugFox/mess/issues + +funding: + - https://www.buymeacoffee.com/plugfox + - https://www.patreon.com/plugfox + - https://boosty.to/plugfox + +topics: + - ECS + - Entity-Component-System + - State Management + - Game Development + - Mass Entity State System + +platforms: + android: + ios: + linux: + macos: + web: + windows: + +#screenshots: +# - description: 'Example of using the library.' +# path: example.png + +environment: + sdk: ^3.5.0 + flutter: ">=3.20.0" + +dependencies: + flutter: + sdk: flutter + # Annotations + meta: ^1.9.1 + +dev_dependencies: + flutter_test: + sdk: flutter + test: ^1.25.0 + fake_async: ^1.3.0 + flutter_lints: '>=4.0.0 <6.0.0' + +flutter: diff --git a/test/unit_test.dart b/test/unit_test.dart new file mode 100644 index 0000000..876e41b --- /dev/null +++ b/test/unit_test.dart @@ -0,0 +1,39 @@ +import 'package:test/test.dart'; + +void main() { + group('Unit', () { + group('Time', () { + test('Seconds', () { + const duration = Duration(seconds: 5); + expect( + duration.inSeconds * Duration.millisecondsPerSecond, + equals(5 * 1000), + ); + expect( + duration.inSeconds * + Duration.millisecondsPerSecond * + Duration.microsecondsPerMillisecond, + equals(5 * 1000 * 1000), + ); + expect( + duration.inSeconds * Duration.microsecondsPerSecond, + equals(5 * 1000 * 1000), + ); + }); + + test('Delta', () { + const elapsed = Duration(seconds: 15); + const previous = Duration(seconds: 14); + final delta = elapsed - previous; + final ms = delta.inMicroseconds / Duration.microsecondsPerMillisecond; + expect(ms, equals(1000)); + }); + + test('Frame rate', () { + const frameRate = 60; + const deltaMs = 1000 / frameRate; + expect(deltaMs, equals(1000 / 60)); + }); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..18ee546 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Widget', () { + testWidgets( + 'Pump Widget', + (tester) async { + await tester.pumpWidget(const MaterialApp(home: Scaffold())); + expect(find.byType(MaterialApp), findsOneWidget); + expect(find.byType(Scaffold), findsOneWidget); + }, + ); + }); +}