diff --git a/.flutter b/.flutter new file mode 100644 index 0000000..010732b --- /dev/null +++ b/.flutter @@ -0,0 +1,3 @@ +{ + "enabled": false +} diff --git a/.flutter_tool_state b/.flutter_tool_state new file mode 100644 index 0000000..f8e1ab1 --- /dev/null +++ b/.flutter_tool_state @@ -0,0 +1,4 @@ +{ + "is-bot": true, + "license-hash": "3e8c85e63b26ce223cda96a9a8fbb410" +} diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json new file mode 100644 index 0000000..ba129cf --- /dev/null +++ b/.fvm/fvm_config.json @@ -0,0 +1,4 @@ +{ + "flutterSdkVersion": "3.10.0", + "flavors": {} +} \ No newline at end of file diff --git a/.github/workflows/build.yml.backup b/.github/workflows/build.yml.backup new file mode 100644 index 0000000..9e867a8 --- /dev/null +++ b/.github/workflows/build.yml.backup @@ -0,0 +1,96 @@ +name: Build +on: push +#on: +# workflow_dispatch: +# release: +# types: [created] + +jobs: + build_macos: + if: ${{ false }} + runs-on: macos-latest + steps: + # Setup + - uses: actions/checkout@v3 + + - uses: subosito/flutter-action@v2 + with: + channel: "stable" +# architecture: x64 + + - uses: actions/setup-node@v2 + + # Install packaging tools + - name: Install flutter_distributor + run: dart pub global activate flutter_distributor + + - name: Install appdmg + run: npm install -g appdmg + + # Build and package + - name: Packaging .dmg .zip + run: flutter_distributor package --platform macos --targets dmg,zip --artifact-name "fterm-${{github.ref_name}}-macos.{{ext}}" + +# # Publish +# - name: Publish to GitHub Release +# uses: softprops/action-gh-release@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# files: dist/*/* + + build_windows: + runs-on: windows-latest + steps: + # Setup + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + architecture: x64 + + # Install packaging tools + - name: Install flutter_distributor + run: dart pub global activate flutter_distributor + + # Build and package + - name: Packaging .msix .zip + run: flutter_distributor package --platform windows --targets msix,exe,zip --artifact-name "fterm-${{github.ref_name}}-windows.{{ext}}" + +# # Publish +# - name: Publish to GitHub Release +# uses: softprops/action-gh-release@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# files: dist/*/* + + build_linux: + runs-on: ubuntu-latest + steps: + # Setup + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + architecture: x64 + + - run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build libgtk-3-dev + + # Install packaging tools + - name: Install flutter_distributor + run: dart pub global activate flutter_distributor + + # Build and package + - name: Packaging .deb .zip + run: flutter_distributor package --platform linux --targets deb,zip --artifact-name "fterm-${{github.ref_name}}-linux.{{ext}}" + +# # Publish +# - name: Publish to GitHub Release +# uses: softprops/action-gh-release@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# files: dist/*/* diff --git a/.github/workflows/build_zip.yml b/.github/workflows/build_zip.yml new file mode 100644 index 0000000..4e6dabd --- /dev/null +++ b/.github/workflows/build_zip.yml @@ -0,0 +1,119 @@ +name: Build +on: + workflow_dispatch: + release: + types: [created] + push: + branches: + - master +# tags: +# - v*.*.* +jobs: + build_macos: + permissions: + contents: write + runs-on: macos-latest + steps: + # Setup + - uses: actions/checkout@v3 + + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + + - name: Install project dependencies + run: flutter pub get + - name: Generate intermediates + run: flutter pub run build_runner build --delete-conflicting-outputs + - name: Enable macos build + run: flutter config --enable-macos-desktop + - name: Build artifacts + run: flutter build macos --release + - name: Archive Release + uses: thedoctor0/zip-release@master + with: + type: 'zip' + filename: fterm-${{github.ref_name}}-macos.zip + directory: build/macos/Build/Products/Release + - name: MaoOS Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: build/macos/Build/Products/Release/fterm-${{github.ref_name}}-macos.zip + + + build_windows: + permissions: + contents: write + runs-on: windows-latest + steps: + # Setup + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + architecture: x64 + + + - name: Install project dependencies + run: flutter pub get + - name: Generate intermediates + run: flutter pub run build_runner build --delete-conflicting-outputs + - name: Enable windows build + run: flutter config --enable-windows-desktop + - name: Build artifacts + run: flutter build windows --release + - name: Archive Release + uses: thedoctor0/zip-release@master + with: + type: 'zip' + filename: fterm-${{github.ref_name}}-windows.zip + directory: build/windows/runner/Release + - name: Windows Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: build/windows/runner/Release/fterm-${{github.ref_name}}-windows.zip + + + build_linux: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + # Setup + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + architecture: x64 + + - run: | + sudo apt-get update -y + sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libjsoncpp-dev libsecret-1-dev + + - name: Install project dependencies + run: flutter pub get + - name: Generate intermediates + run: flutter pub run build_runner build --delete-conflicting-outputs + - name: Enable linux build + run: flutter config --enable-linux-desktop + - name: Build artifacts + run: flutter build linux --release + - name: Archive Release + uses: thedoctor0/zip-release@master + with: + type: 'zip' + filename: fterm-${{github.ref_name}}-linux.zip + directory: build/linux/x64/release/bundle + - name: Linux Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: build/linux/x64/release/bundle/fterm-${{github.ref_name}}-linux.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c90798 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# 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/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# 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 +.fvm/flutter_sdk +.idea +target +/dist diff --git a/.linux.env b/.linux.env new file mode 100644 index 0000000..b9db904 --- /dev/null +++ b/.linux.env @@ -0,0 +1,2 @@ +http_proxy=http://192.168.50.247:7890 +https_proxy=http://192.168.50.247:7890 diff --git a/.mac.env b/.mac.env new file mode 100644 index 0000000..4e50e34 --- /dev/null +++ b/.mac.env @@ -0,0 +1,2 @@ +http_proxy=http://192.168.60.14:7890 +https_proxy=http://192.168.60.14:7890 diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..7772fa1 --- /dev/null +++ b/.metadata @@ -0,0 +1,36 @@ +# 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. + +version: + revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + - platform: linux + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + - platform: macos + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + - platform: windows + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.windows.env b/.windows.env new file mode 100644 index 0000000..b9db904 --- /dev/null +++ b/.windows.env @@ -0,0 +1,2 @@ +http_proxy=http://192.168.50.247:7890 +https_proxy=http://192.168.50.247:7890 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a2c8eb1 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +gen: + fvm flutter pub run build_runner build --delete-conflicting-outputs + +check_update: + fvm flutter pub upgrade --major-versions + fvm flutter pub get +clean: + fvm flutter clean +windows: clean + act --container-architecture linux/amd64 --env-file .windows.env -P windows-latest=-self-hosted -j build_windows +macos: clean + act --container-architecture linux/amd64 --env-file .macos.env -P macos-latest=-self-hosted -j build_macos +linux: clean + act --container-architecture linux/amd64 --env-file .linux.env -P ubuntu-latest=-self-hosted -j build_linux +init: + cargo install flutter_rust_bridge_codegen + cargo install cargo-xcode + cargo install cargo-make +act: + act --container-architecture linux/amd64 --env-file .env diff --git a/README.md b/README.md new file mode 100644 index 0000000..b534b6a --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# fterm + +fterm是一款基于Flutter开发的跨平台终端工具 + +# 功能 +- [x] 本地终端 +- [x] 多种主题颜色 +- [x] ssh主机连接 +- [x] ssh配置本地加密存储 +- [x] 通过ssh跳板机连接目标主机 +- [x] 支持zmodem +- [ ] ssh配置多端同步 + + + +# 部分截图 +![fterm1](resources/fterm1.png) +![fterm2](resources/fterm2.png) +![fterm3](resources/fterm3.png) +![fterm4](resources/fterm4.png) +![fterm5](resources/fterm5.png) +![fterm6](resources/fterm6.png) diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/assets/colors/schemes/3024 Day b/assets/colors/schemes/3024 Day new file mode 100644 index 0000000..b736210 --- /dev/null +++ b/assets/colors/schemes/3024 Day @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #4a4543 +*.background: #f7f7f7 +*.cursorColor: #4a4543 +! +! Black +*.color0: #090300 +*.color8: #5c5855 +! +! Red +*.color1: #db2d20 +*.color9: #e8bbd0 +! +! Green +*.color2: #01a252 +*.color10: #3a3432 +! +! Yellow +*.color3: #fded02 +*.color11: #4a4543 +! +! Blue +*.color4: #01a0e4 +*.color12: #807d7c +! +! Magenta +*.color5: #a16a94 +*.color13: #d6d5d4 +! +! Cyan +*.color6: #b5e4f4 +*.color14: #cdab53 +! +! White +*.color7: #a5a2a2 +*.color15: #f7f7f7 +! +! Bold, Italic, Underline +*.colorBD: #4a4543 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/3024 Night b/assets/colors/schemes/3024 Night new file mode 100644 index 0000000..6f559f3 --- /dev/null +++ b/assets/colors/schemes/3024 Night @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a5a2a2 +*.background: #090300 +*.cursorColor: #a5a2a2 +! +! Black +*.color0: #090300 +*.color8: #5c5855 +! +! Red +*.color1: #db2d20 +*.color9: #e8bbd0 +! +! Green +*.color2: #01a252 +*.color10: #3a3432 +! +! Yellow +*.color3: #fded02 +*.color11: #4a4543 +! +! Blue +*.color4: #01a0e4 +*.color12: #807d7c +! +! Magenta +*.color5: #a16a94 +*.color13: #d6d5d4 +! +! Cyan +*.color6: #b5e4f4 +*.color14: #cdab53 +! +! White +*.color7: #a5a2a2 +*.color15: #f7f7f7 +! +! Bold, Italic, Underline +*.colorBD: #a5a2a2 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/AdventureTime b/assets/colors/schemes/AdventureTime new file mode 100644 index 0000000..e8b9516 --- /dev/null +++ b/assets/colors/schemes/AdventureTime @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f8dcc0 +*.background: #1f1d45 +*.cursorColor: #efbf38 +! +! Black +*.color0: #050404 +*.color8: #4e7cbf +! +! Red +*.color1: #bd0013 +*.color9: #fc5f5a +! +! Green +*.color2: #4ab118 +*.color10: #9eff6e +! +! Yellow +*.color3: #e7741e +*.color11: #efc11a +! +! Blue +*.color4: #0f4ac6 +*.color12: #1997c6 +! +! Magenta +*.color5: #665993 +*.color13: #9b5953 +! +! Cyan +*.color6: #70a598 +*.color14: #c8faf4 +! +! White +*.color7: #f8dcc0 +*.color15: #f6f5fb +! +! Bold, Italic, Underline +*.colorBD: #bd0013 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Afterglow b/assets/colors/schemes/Afterglow new file mode 100644 index 0000000..be2d0ae --- /dev/null +++ b/assets/colors/schemes/Afterglow @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d0d0d0 +*.background: #212121 +*.cursorColor: #d0d0d0 +! +! Black +*.color0: #151515 +*.color8: #505050 +! +! Red +*.color1: #ac4142 +*.color9: #ac4142 +! +! Green +*.color2: #7e8e50 +*.color10: #7e8e50 +! +! Yellow +*.color3: #e5b567 +*.color11: #e5b567 +! +! Blue +*.color4: #6c99bb +*.color12: #6c99bb +! +! Magenta +*.color5: #9f4e85 +*.color13: #9f4e85 +! +! Cyan +*.color6: #7dd6cf +*.color14: #7dd6cf +! +! White +*.color7: #d0d0d0 +*.color15: #f5f5f5 +! +! Bold, Italic, Underline +*.colorBD: #d0d0d0 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/AlienBlood b/assets/colors/schemes/AlienBlood new file mode 100644 index 0000000..967056a --- /dev/null +++ b/assets/colors/schemes/AlienBlood @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #637d75 +*.background: #0f1610 +*.cursorColor: #73fa91 +! +! Black +*.color0: #112616 +*.color8: #3c4812 +! +! Red +*.color1: #7f2b27 +*.color9: #e08009 +! +! Green +*.color2: #2f7e25 +*.color10: #18e000 +! +! Yellow +*.color3: #717f24 +*.color11: #bde000 +! +! Blue +*.color4: #2f6a7f +*.color12: #00aae0 +! +! Magenta +*.color5: #47587f +*.color13: #0058e0 +! +! Cyan +*.color6: #327f77 +*.color14: #00e0c4 +! +! White +*.color7: #647d75 +*.color15: #73fa91 +! +! Bold, Italic, Underline +*.colorBD: #7afa87 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Argonaut b/assets/colors/schemes/Argonaut new file mode 100644 index 0000000..5a85173 --- /dev/null +++ b/assets/colors/schemes/Argonaut @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #fffaf4 +*.background: #0e1019 +*.cursorColor: #ff0018 +! +! Black +*.color0: #232323 +*.color8: #444444 +! +! Red +*.color1: #ff000f +*.color9: #ff2740 +! +! Green +*.color2: #8ce10b +*.color10: #abe15b +! +! Yellow +*.color3: #ffb900 +*.color11: #ffd242 +! +! Blue +*.color4: #008df8 +*.color12: #0092ff +! +! Magenta +*.color5: #6d43a6 +*.color13: #9a5feb +! +! Cyan +*.color6: #00d8eb +*.color14: #67fff0 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #9e9c9a +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Arthur b/assets/colors/schemes/Arthur new file mode 100644 index 0000000..b8a2266 --- /dev/null +++ b/assets/colors/schemes/Arthur @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ddeedd +*.background: #1c1c1c +*.cursorColor: #e2bbef +! +! Black +*.color0: #3d352a +*.color8: #554444 +! +! Red +*.color1: #cd5c5c +*.color9: #cc5533 +! +! Green +*.color2: #86af80 +*.color10: #88aa22 +! +! Yellow +*.color3: #e8ae5b +*.color11: #ffa75d +! +! Blue +*.color4: #6495ed +*.color12: #87ceeb +! +! Magenta +*.color5: #deb887 +*.color13: #996600 +! +! Cyan +*.color6: #b0c4de +*.color14: #b0c4de +! +! White +*.color7: #bbaa99 +*.color15: #ddccbb +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/AtelierSulphurpool b/assets/colors/schemes/AtelierSulphurpool new file mode 100644 index 0000000..8979d8f --- /dev/null +++ b/assets/colors/schemes/AtelierSulphurpool @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #979db4 +*.background: #202746 +*.cursorColor: #979db4 +! +! Black +*.color0: #202746 +*.color8: #6b7394 +! +! Red +*.color1: #c94922 +*.color9: #c76b29 +! +! Green +*.color2: #ac9739 +*.color10: #293256 +! +! Yellow +*.color3: #c08b30 +*.color11: #5e6687 +! +! Blue +*.color4: #3d8fd1 +*.color12: #898ea4 +! +! Magenta +*.color5: #6679cc +*.color13: #dfe2f1 +! +! Cyan +*.color6: #22a2c9 +*.color14: #9c637a +! +! White +*.color7: #979db4 +*.color15: #f5f7ff +! +! Bold, Italic, Underline +*.colorBD: #979db4 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Atom b/assets/colors/schemes/Atom new file mode 100644 index 0000000..43c7418 --- /dev/null +++ b/assets/colors/schemes/Atom @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c5c8c6 +*.background: #161719 +*.cursorColor: #d0d0d0 +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #fd5ff1 +*.color9: #fd5ff1 +! +! Green +*.color2: #87c38a +*.color10: #94fa36 +! +! Yellow +*.color3: #ffd7b1 +*.color11: #f5ffa8 +! +! Blue +*.color4: #85befd +*.color12: #96cbfe +! +! Magenta +*.color5: #b9b6fc +*.color13: #b9b6fc +! +! Cyan +*.color6: #85befd +*.color14: #85befd +! +! White +*.color7: #e0e0e0 +*.color15: #e0e0e0 +! +! Bold, Italic, Underline +*.colorBD: #c5c8c6 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/AtomOneLight b/assets/colors/schemes/AtomOneLight new file mode 100644 index 0000000..cfd341b --- /dev/null +++ b/assets/colors/schemes/AtomOneLight @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #2a2c33 +*.background: #f9f9f9 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #de3e35 +*.color9: #de3e35 +! +! Green +*.color2: #3f953a +*.color10: #3f953a +! +! Yellow +*.color3: #d2b67c +*.color11: #d2b67c +! +! Blue +*.color4: #2f5af3 +*.color12: #2f5af3 +! +! Magenta +*.color5: #950095 +*.color13: #a00095 +! +! Cyan +*.color6: #3f953a +*.color14: #3f953a +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #000000 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Base16 Default Dark b/assets/colors/schemes/Base16 Default Dark new file mode 100644 index 0000000..413a1e8 --- /dev/null +++ b/assets/colors/schemes/Base16 Default Dark @@ -0,0 +1,54 @@ +! Base16 Default Dark +! Scheme: Chris Kempson (http://chriskempson.com) + +#define base00 #181818 +#define base01 #282828 +#define base02 #383838 +#define base03 #585858 +#define base04 #b8b8b8 +#define base05 #d8d8d8 +#define base06 #e8e8e8 +#define base07 #f8f8f8 +#define base08 #ab4642 +#define base09 #dc9656 +#define base0A #f7ca88 +#define base0B #a1b56c +#define base0C #86c1b9 +#define base0D #7cafc2 +#define base0E #ba8baf +#define base0F #a16946 + +*.foreground: base05 +#ifdef background_opacity +*.background: [background_opacity]base00 +#else +*.background: base00 +#endif +*.cursorColor: base05 + +*.color0: base00 +*.color1: base08 +*.color2: base0B +*.color3: base0A +*.color4: base0D +*.color5: base0E +*.color6: base0C +*.color7: base05 + +*.color8: base03 +*.color9: base08 +*.color10: base0B +*.color11: base0A +*.color12: base0D +*.color13: base0E +*.color14: base0C +*.color15: base07 + +! Note: colors beyond 15 might not be loaded (e.g., xterm, urxvt), +! use 'shell' template to set these if necessary +*.color16: base09 +*.color17: base0F +*.color18: base01 +*.color19: base02 +*.color20: base04 +*.color21: base06 diff --git a/assets/colors/schemes/Batman b/assets/colors/schemes/Batman new file mode 100644 index 0000000..a99d7bb --- /dev/null +++ b/assets/colors/schemes/Batman @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #6f6f6f +*.background: #1b1d1e +*.cursorColor: #fcef0c +! +! Black +*.color0: #1b1d1e +*.color8: #505354 +! +! Red +*.color1: #e6dc44 +*.color9: #fff78e +! +! Green +*.color2: #c8be46 +*.color10: #fff27d +! +! Yellow +*.color3: #f4fd22 +*.color11: #feed6c +! +! Blue +*.color4: #737174 +*.color12: #919495 +! +! Magenta +*.color5: #747271 +*.color13: #9a9a9d +! +! Cyan +*.color6: #62605f +*.color14: #a3a3a6 +! +! White +*.color7: #c6c5bf +*.color15: #dadbd6 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Belafonte Day b/assets/colors/schemes/Belafonte Day new file mode 100644 index 0000000..e833b3e --- /dev/null +++ b/assets/colors/schemes/Belafonte Day @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #45373c +*.background: #d5ccba +*.cursorColor: #45373c +! +! Black +*.color0: #20111b +*.color8: #5e5252 +! +! Red +*.color1: #be100e +*.color9: #be100e +! +! Green +*.color2: #858162 +*.color10: #858162 +! +! Yellow +*.color3: #eaa549 +*.color11: #eaa549 +! +! Blue +*.color4: #426a79 +*.color12: #426a79 +! +! Magenta +*.color5: #97522c +*.color13: #97522c +! +! Cyan +*.color6: #989a9c +*.color14: #989a9c +! +! White +*.color7: #968c83 +*.color15: #d5ccba +! +! Bold, Italic, Underline +*.colorBD: #45373c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Belafonte Night b/assets/colors/schemes/Belafonte Night new file mode 100644 index 0000000..b1c1f4e --- /dev/null +++ b/assets/colors/schemes/Belafonte Night @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #968c83 +*.background: #20111b +*.cursorColor: #968c83 +! +! Black +*.color0: #20111b +*.color8: #5e5252 +! +! Red +*.color1: #be100e +*.color9: #be100e +! +! Green +*.color2: #858162 +*.color10: #858162 +! +! Yellow +*.color3: #eaa549 +*.color11: #eaa549 +! +! Blue +*.color4: #426a79 +*.color12: #426a79 +! +! Magenta +*.color5: #97522c +*.color13: #97522c +! +! Cyan +*.color6: #989a9c +*.color14: #989a9c +! +! White +*.color7: #968c83 +*.color15: #d5ccba +! +! Bold, Italic, Underline +*.colorBD: #968c83 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/BirdsOfParadise b/assets/colors/schemes/BirdsOfParadise new file mode 100644 index 0000000..78a5e5a --- /dev/null +++ b/assets/colors/schemes/BirdsOfParadise @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e0dbb7 +*.background: #2a1f1d +*.cursorColor: #573d26 +! +! Black +*.color0: #573d26 +*.color8: #9b6c4a +! +! Red +*.color1: #be2d26 +*.color9: #e84627 +! +! Green +*.color2: #6ba18a +*.color10: #95d8ba +! +! Yellow +*.color3: #e99d2a +*.color11: #d0d150 +! +! Blue +*.color4: #5a86ad +*.color12: #b8d3ed +! +! Magenta +*.color5: #ac80a6 +*.color13: #d19ecb +! +! Cyan +*.color6: #74a6ad +*.color14: #93cfd7 +! +! White +*.color7: #e0dbb7 +*.color15: #fff9d5 +! +! Bold, Italic, Underline +*.colorBD: #fff8d8 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Blazer b/assets/colors/schemes/Blazer new file mode 100644 index 0000000..2863dab --- /dev/null +++ b/assets/colors/schemes/Blazer @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d9e6f2 +*.background: #0d1926 +*.cursorColor: #d9e6f2 +! +! Black +*.color0: #000000 +*.color8: #262626 +! +! Red +*.color1: #b87a7a +*.color9: #dbbdbd +! +! Green +*.color2: #7ab87a +*.color10: #bddbbd +! +! Yellow +*.color3: #b8b87a +*.color11: #dbdbbd +! +! Blue +*.color4: #7a7ab8 +*.color12: #bdbddb +! +! Magenta +*.color5: #b87ab8 +*.color13: #dbbddb +! +! Cyan +*.color6: #7ab8b8 +*.color14: #bddbdb +! +! White +*.color7: #d9d9d9 +*.color15: #ffffff +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Borland b/assets/colors/schemes/Borland new file mode 100644 index 0000000..7e3ea72 --- /dev/null +++ b/assets/colors/schemes/Borland @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffff4e +*.background: #0000a4 +*.cursorColor: #ffa560 +! +! Black +*.color0: #4f4f4f +*.color8: #7c7c7c +! +! Red +*.color1: #ff6c60 +*.color9: #ffb6b0 +! +! Green +*.color2: #a8ff60 +*.color10: #ceffac +! +! Yellow +*.color3: #ffffb6 +*.color11: #ffffcc +! +! Blue +*.color4: #96cbfe +*.color12: #b5dcff +! +! Magenta +*.color5: #ff73fd +*.color13: #ff9cfe +! +! Cyan +*.color6: #c6c5fe +*.color14: #dfdffe +! +! White +*.color7: #eeeeee +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffff4e +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Bright Lights b/assets/colors/schemes/Bright Lights new file mode 100644 index 0000000..0734095 --- /dev/null +++ b/assets/colors/schemes/Bright Lights @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b3c9d7 +*.background: #191919 +*.cursorColor: #f34b00 +! +! Black +*.color0: #191919 +*.color8: #191919 +! +! Red +*.color1: #ff355b +*.color9: #ff355b +! +! Green +*.color2: #b7e876 +*.color10: #b7e876 +! +! Yellow +*.color3: #ffc251 +*.color11: #ffc251 +! +! Blue +*.color4: #76d4ff +*.color12: #76d5ff +! +! Magenta +*.color5: #ba76e7 +*.color13: #ba76e7 +! +! Cyan +*.color6: #6cbfb5 +*.color14: #6cbfb5 +! +! White +*.color7: #c2c8d7 +*.color15: #c2c8d7 +! +! Bold, Italic, Underline +*.colorBD: #9fb3c1 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Broadcast b/assets/colors/schemes/Broadcast new file mode 100644 index 0000000..0ce4192 --- /dev/null +++ b/assets/colors/schemes/Broadcast @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e6e1dc +*.background: #2b2b2b +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #323232 +! +! Red +*.color1: #da4939 +*.color9: #ff7b6b +! +! Green +*.color2: #519f50 +*.color10: #83d182 +! +! Yellow +*.color3: #ffd24a +*.color11: #ffff7c +! +! Blue +*.color4: #6d9cbe +*.color12: #9fcef0 +! +! Magenta +*.color5: #d0d0ff +*.color13: #ffffff +! +! Cyan +*.color6: #6e9cbe +*.color14: #a0cef0 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #e6e1dc +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Brogrammer b/assets/colors/schemes/Brogrammer new file mode 100644 index 0000000..0634c56 --- /dev/null +++ b/assets/colors/schemes/Brogrammer @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d6dbe5 +*.background: #131313 +*.cursorColor: #b9b9b9 +! +! Black +*.color0: #1f1f1f +*.color8: #d6dbe5 +! +! Red +*.color1: #f81118 +*.color9: #de352e +! +! Green +*.color2: #2dc55e +*.color10: #1dd361 +! +! Yellow +*.color3: #ecba0f +*.color11: #f3bd09 +! +! Blue +*.color4: #2a84d2 +*.color12: #1081d6 +! +! Magenta +*.color5: #4e5ab7 +*.color13: #5350b9 +! +! Cyan +*.color6: #1081d6 +*.color14: #0f7ddb +! +! White +*.color7: #d6dbe5 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #d6dbe5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/C64 b/assets/colors/schemes/C64 new file mode 100644 index 0000000..0ca8a7b --- /dev/null +++ b/assets/colors/schemes/C64 @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #7869c4 +*.background: #40318d +*.cursorColor: #7869c4 +! +! Black +*.color0: #090300 +*.color8: #000000 +! +! Red +*.color1: #883932 +*.color9: #883932 +! +! Green +*.color2: #55a049 +*.color10: #55a049 +! +! Yellow +*.color3: #bfce72 +*.color11: #bfce72 +! +! Blue +*.color4: #40318d +*.color12: #40318d +! +! Magenta +*.color5: #8b3f96 +*.color13: #8b3f96 +! +! Cyan +*.color6: #67b6bd +*.color14: #67b6bd +! +! White +*.color7: #ffffff +*.color15: #f7f7f7 +! +! Bold, Italic, Underline +*.colorBD: #a5a2a2 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/CLRS b/assets/colors/schemes/CLRS new file mode 100644 index 0000000..05932c1 --- /dev/null +++ b/assets/colors/schemes/CLRS @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #262626 +*.background: #ffffff +*.cursorColor: #6fd3fc +! +! Black +*.color0: #000000 +*.color8: #555753 +! +! Red +*.color1: #f8282a +*.color9: #fb0416 +! +! Green +*.color2: #328a5d +*.color10: #2cc631 +! +! Yellow +*.color3: #fa701d +*.color11: #fdd727 +! +! Blue +*.color4: #135cd0 +*.color12: #1670ff +! +! Magenta +*.color5: #9f00bd +*.color13: #e900b0 +! +! Cyan +*.color6: #33c3c1 +*.color14: #3ad5ce +! +! White +*.color7: #b3b3b3 +*.color15: #eeeeec +! +! Bold, Italic, Underline +*.colorBD: #1a1a1a +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Chalk b/assets/colors/schemes/Chalk new file mode 100644 index 0000000..4739464 --- /dev/null +++ b/assets/colors/schemes/Chalk @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d2d8d9 +*.background: #2b2d2e +*.cursorColor: #708284 +! +! Black +*.color0: #7d8b8f +*.color8: #888888 +! +! Red +*.color1: #b23a52 +*.color9: #f24840 +! +! Green +*.color2: #789b6a +*.color10: #80c470 +! +! Yellow +*.color3: #b9ac4a +*.color11: #ffeb62 +! +! Blue +*.color4: #2a7fac +*.color12: #4196ff +! +! Magenta +*.color5: #bd4f5a +*.color13: #fc5275 +! +! Cyan +*.color6: #44a799 +*.color14: #53cdbd +! +! White +*.color7: #d2d8d9 +*.color15: #d2d8d9 +! +! Bold, Italic, Underline +*.colorBD: #ececec +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Chalkboard b/assets/colors/schemes/Chalkboard new file mode 100644 index 0000000..31605d0 --- /dev/null +++ b/assets/colors/schemes/Chalkboard @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d9e6f2 +*.background: #29262f +*.cursorColor: #d9e6f2 +! +! Black +*.color0: #000000 +*.color8: #323232 +! +! Red +*.color1: #c37372 +*.color9: #dbaaaa +! +! Green +*.color2: #72c373 +*.color10: #aadbaa +! +! Yellow +*.color3: #c2c372 +*.color11: #dadbaa +! +! Blue +*.color4: #7372c3 +*.color12: #aaaadb +! +! Magenta +*.color5: #c372c2 +*.color13: #dbaada +! +! Cyan +*.color6: #72c2c3 +*.color14: #aadadb +! +! White +*.color7: #d9d9d9 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #d96f5f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Ciapre b/assets/colors/schemes/Ciapre new file mode 100644 index 0000000..9d19131 --- /dev/null +++ b/assets/colors/schemes/Ciapre @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #aea47a +*.background: #191c27 +*.cursorColor: #92805b +! +! Black +*.color0: #181818 +*.color8: #555555 +! +! Red +*.color1: #810009 +*.color9: #ac3835 +! +! Green +*.color2: #48513b +*.color10: #a6a75d +! +! Yellow +*.color3: #cc8b3f +*.color11: #dcdf7c +! +! Blue +*.color4: #576d8c +*.color12: #3097c6 +! +! Magenta +*.color5: #724d7c +*.color13: #d33061 +! +! Cyan +*.color6: #5c4f4b +*.color14: #f3dbb2 +! +! White +*.color7: #aea47f +*.color15: #f4f4f4 +! +! Bold, Italic, Underline +*.colorBD: #f4f4f4 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Cobalt Neon b/assets/colors/schemes/Cobalt Neon new file mode 100644 index 0000000..95ce657 --- /dev/null +++ b/assets/colors/schemes/Cobalt Neon @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #8ff586 +*.background: #142838 +*.cursorColor: #c4206f +! +! Black +*.color0: #142631 +*.color8: #fff688 +! +! Red +*.color1: #ff2320 +*.color9: #d4312e +! +! Green +*.color2: #3ba5ff +*.color10: #8ff586 +! +! Yellow +*.color3: #e9e75c +*.color11: #e9f06d +! +! Blue +*.color4: #8ff586 +*.color12: #3c7dd2 +! +! Magenta +*.color5: #781aa0 +*.color13: #8230a7 +! +! Cyan +*.color6: #8ff586 +*.color14: #6cbc67 +! +! White +*.color7: #ba46b2 +*.color15: #8ff586 +! +! Bold, Italic, Underline +*.colorBD: #248b70 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Cobalt2 b/assets/colors/schemes/Cobalt2 new file mode 100644 index 0000000..0e6259d --- /dev/null +++ b/assets/colors/schemes/Cobalt2 @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #132738 +*.cursorColor: #f0cc09 +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #ff0000 +*.color9: #f40e17 +! +! Green +*.color2: #38de21 +*.color10: #3bd01d +! +! Yellow +*.color3: #ffe50a +*.color11: #edc809 +! +! Blue +*.color4: #1460d2 +*.color12: #5555ff +! +! Magenta +*.color5: #ff005d +*.color13: #ff55ff +! +! Cyan +*.color6: #00bbbb +*.color14: #6ae3fa +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #f7fcff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/CrayonPonyFish b/assets/colors/schemes/CrayonPonyFish new file mode 100644 index 0000000..15f14db --- /dev/null +++ b/assets/colors/schemes/CrayonPonyFish @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #68525a +*.background: #150707 +*.cursorColor: #68525a +! +! Black +*.color0: #2b1b1d +*.color8: #3d2b2e +! +! Red +*.color1: #91002b +*.color9: #c5255d +! +! Green +*.color2: #579524 +*.color10: #8dff57 +! +! Yellow +*.color3: #ab311b +*.color11: #c8381d +! +! Blue +*.color4: #8c87b0 +*.color12: #cfc9ff +! +! Magenta +*.color5: #692f50 +*.color13: #fc6cba +! +! Cyan +*.color6: #e8a866 +*.color14: #ffceaf +! +! White +*.color7: #68525a +*.color15: #b0949d +! +! Bold, Italic, Underline +*.colorBD: #c8381d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Dark Pastel b/assets/colors/schemes/Dark Pastel new file mode 100644 index 0000000..a2aefcf --- /dev/null +++ b/assets/colors/schemes/Dark Pastel @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #000000 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #ff5555 +*.color9: #ff5555 +! +! Green +*.color2: #55ff55 +*.color10: #55ff55 +! +! Yellow +*.color3: #ffff55 +*.color11: #ffff55 +! +! Blue +*.color4: #5555ff +*.color12: #5555ff +! +! Magenta +*.color5: #ff55ff +*.color13: #ff55ff +! +! Cyan +*.color6: #55ffff +*.color14: #55ffff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ff5e7d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Darkside b/assets/colors/schemes/Darkside new file mode 100644 index 0000000..225685a --- /dev/null +++ b/assets/colors/schemes/Darkside @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bababa +*.background: #222324 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #e8341c +*.color9: #e05a4f +! +! Green +*.color2: #68c256 +*.color10: #77b869 +! +! Yellow +*.color3: #f2d42c +*.color11: #efd64b +! +! Blue +*.color4: #1c98e8 +*.color12: #387cd3 +! +! Magenta +*.color5: #8e69c9 +*.color13: #957bbe +! +! Cyan +*.color6: #1c98e8 +*.color14: #3d97e2 +! +! White +*.color7: #bababa +*.color15: #bababa +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Desert b/assets/colors/schemes/Desert new file mode 100644 index 0000000..24be2c0 --- /dev/null +++ b/assets/colors/schemes/Desert @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #333333 +*.cursorColor: #00ff00 +! +! Black +*.color0: #4d4d4d +*.color8: #555555 +! +! Red +*.color1: #ff2b2b +*.color9: #ff5555 +! +! Green +*.color2: #98fb98 +*.color10: #55ff55 +! +! Yellow +*.color3: #f0e68c +*.color11: #ffff55 +! +! Blue +*.color4: #cd853f +*.color12: #87ceff +! +! Magenta +*.color5: #ffdead +*.color13: #ff55ff +! +! Cyan +*.color6: #ffa0a0 +*.color14: #ffd700 +! +! White +*.color7: #f5deb3 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffd700 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/DimmedMonokai b/assets/colors/schemes/DimmedMonokai new file mode 100644 index 0000000..74d7ed1 --- /dev/null +++ b/assets/colors/schemes/DimmedMonokai @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b9bcba +*.background: #1f1f1f +*.cursorColor: #f83e19 +! +! Black +*.color0: #3a3d43 +*.color8: #888987 +! +! Red +*.color1: #be3f48 +*.color9: #fb001f +! +! Green +*.color2: #879a3b +*.color10: #0f722f +! +! Yellow +*.color3: #c5a635 +*.color11: #c47033 +! +! Blue +*.color4: #4f76a1 +*.color12: #186de3 +! +! Magenta +*.color5: #855c8d +*.color13: #fb0067 +! +! Cyan +*.color6: #578fa4 +*.color14: #2e706d +! +! White +*.color7: #b9bcba +*.color15: #fdffb9 +! +! Bold, Italic, Underline +*.colorBD: #feffb2 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/DotGov b/assets/colors/schemes/DotGov new file mode 100644 index 0000000..c718426 --- /dev/null +++ b/assets/colors/schemes/DotGov @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ebebeb +*.background: #262c35 +*.cursorColor: #d9002f +! +! Black +*.color0: #191919 +*.color8: #191919 +! +! Red +*.color1: #bf091d +*.color9: #bf091d +! +! Green +*.color2: #3d9751 +*.color10: #3d9751 +! +! Yellow +*.color3: #f6bb34 +*.color11: #f6bb34 +! +! Blue +*.color4: #17b2e0 +*.color12: #17b2e0 +! +! Magenta +*.color5: #7830b0 +*.color13: #7830b0 +! +! Cyan +*.color6: #8bd2ed +*.color14: #8bd2ed +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #fbab19 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Dracula b/assets/colors/schemes/Dracula new file mode 100644 index 0000000..4403061 --- /dev/null +++ b/assets/colors/schemes/Dracula @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f8f8f2 +*.background: #1e1f29 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #ff5555 +*.color9: #ff5555 +! +! Green +*.color2: #50fa7b +*.color10: #50fa7b +! +! Yellow +*.color3: #f1fa8c +*.color11: #f1fa8c +! +! Blue +*.color4: #bd93f9 +*.color12: #bd93f9 +! +! Magenta +*.color5: #ff79c6 +*.color13: #ff79c6 +! +! Cyan +*.color6: #8be9fd +*.color14: #8be9fd +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Duotone Dark b/assets/colors/schemes/Duotone Dark new file mode 100644 index 0000000..33b27fb --- /dev/null +++ b/assets/colors/schemes/Duotone Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b7a1ff +*.background: #1f1d27 +*.cursorColor: #ff9839 +! +! Black +*.color0: #1f1d27 +*.color8: #353147 +! +! Red +*.color1: #d9393e +*.color9: #d9393e +! +! Green +*.color2: #2dcd73 +*.color10: #2dcd73 +! +! Yellow +*.color3: #d9b76e +*.color11: #d9b76e +! +! Blue +*.color4: #ffc284 +*.color12: #ffc284 +! +! Magenta +*.color5: #de8d40 +*.color13: #de8d40 +! +! Cyan +*.color6: #2488ff +*.color14: #2488ff +! +! White +*.color7: #b7a1ff +*.color15: #eae5ff +! +! Bold, Italic, Underline +*.colorBD: #b7a2ff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/ENCOM b/assets/colors/schemes/ENCOM new file mode 100644 index 0000000..df093a4 --- /dev/null +++ b/assets/colors/schemes/ENCOM @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #00a595 +*.background: #000000 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #9f0000 +*.color9: #ff0000 +! +! Green +*.color2: #008b00 +*.color10: #00ee00 +! +! Yellow +*.color3: #ffd000 +*.color11: #ffff00 +! +! Blue +*.color4: #0081ff +*.color12: #0000ff +! +! Magenta +*.color5: #bc00ca +*.color13: #ff00ff +! +! Cyan +*.color6: #008b8b +*.color14: #00cdcd +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #4cf1e1 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Earthsong b/assets/colors/schemes/Earthsong new file mode 100644 index 0000000..5152230 --- /dev/null +++ b/assets/colors/schemes/Earthsong @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e5c7a9 +*.background: #292520 +*.cursorColor: #f6f7ec +! +! Black +*.color0: #121418 +*.color8: #675f54 +! +! Red +*.color1: #c94234 +*.color9: #ff645a +! +! Green +*.color2: #85c54c +*.color10: #98e036 +! +! Yellow +*.color3: #f5ae2e +*.color11: #e0d561 +! +! Blue +*.color4: #1398b9 +*.color12: #5fdaff +! +! Magenta +*.color5: #d0633d +*.color13: #ff9269 +! +! Cyan +*.color6: #509552 +*.color14: #84f088 +! +! White +*.color7: #e5c6aa +*.color15: #f6f7ec +! +! Bold, Italic, Underline +*.colorBD: #f6f7ec +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Elemental b/assets/colors/schemes/Elemental new file mode 100644 index 0000000..3548aee --- /dev/null +++ b/assets/colors/schemes/Elemental @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #807a74 +*.background: #22211d +*.cursorColor: #facb80 +! +! Black +*.color0: #3c3c30 +*.color8: #555445 +! +! Red +*.color1: #98290f +*.color9: #e0502a +! +! Green +*.color2: #479a43 +*.color10: #61e070 +! +! Yellow +*.color3: #7f7111 +*.color11: #d69927 +! +! Blue +*.color4: #497f7d +*.color12: #79d9d9 +! +! Magenta +*.color5: #7f4e2f +*.color13: #cd7c54 +! +! Cyan +*.color6: #387f58 +*.color14: #59d599 +! +! White +*.color7: #807974 +*.color15: #fff1e9 +! +! Bold, Italic, Underline +*.colorBD: #fae679 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Elementary b/assets/colors/schemes/Elementary new file mode 100644 index 0000000..64fc622 --- /dev/null +++ b/assets/colors/schemes/Elementary @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #efefef +*.background: #181818 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #242424 +*.color8: #4b4b4b +! +! Red +*.color1: #d71c15 +*.color9: #fc1c18 +! +! Green +*.color2: #5aa513 +*.color10: #6bc219 +! +! Yellow +*.color3: #fdb40c +*.color11: #fec80e +! +! Blue +*.color4: #063b8c +*.color12: #0955ff +! +! Magenta +*.color5: #e40038 +*.color13: #fb0050 +! +! Cyan +*.color6: #2595e1 +*.color14: #3ea8fc +! +! White +*.color7: #efefef +*.color15: #8c00ec +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Espresso b/assets/colors/schemes/Espresso new file mode 100644 index 0000000..2068597 --- /dev/null +++ b/assets/colors/schemes/Espresso @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #323232 +*.cursorColor: #d6d6d6 +! +! Black +*.color0: #353535 +*.color8: #535353 +! +! Red +*.color1: #d25252 +*.color9: #f00c0c +! +! Green +*.color2: #a5c261 +*.color10: #c2e075 +! +! Yellow +*.color3: #ffc66d +*.color11: #e1e48b +! +! Blue +*.color4: #6c99bb +*.color12: #8ab7d9 +! +! Magenta +*.color5: #d197d9 +*.color13: #efb5f7 +! +! Cyan +*.color6: #bed6ff +*.color14: #dcf4ff +! +! White +*.color7: #eeeeec +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Espresso Libre b/assets/colors/schemes/Espresso Libre new file mode 100644 index 0000000..e488ca1 --- /dev/null +++ b/assets/colors/schemes/Espresso Libre @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b8a898 +*.background: #2a211c +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #555753 +! +! Red +*.color1: #cc0000 +*.color9: #ef2929 +! +! Green +*.color2: #1a921c +*.color10: #9aff87 +! +! Yellow +*.color3: #f0e53a +*.color11: #fffb5c +! +! Blue +*.color4: #0066ff +*.color12: #43a8ed +! +! Magenta +*.color5: #c5656b +*.color13: #ff818a +! +! Cyan +*.color6: #06989a +*.color14: #34e2e2 +! +! White +*.color7: #d3d7cf +*.color15: #eeeeec +! +! Bold, Italic, Underline +*.colorBD: #d3c1af +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Fideloper b/assets/colors/schemes/Fideloper new file mode 100644 index 0000000..aa15cb7 --- /dev/null +++ b/assets/colors/schemes/Fideloper @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dbdae0 +*.background: #292f33 +*.cursorColor: #d4605a +! +! Black +*.color0: #292f33 +*.color8: #092028 +! +! Red +*.color1: #cb1e2d +*.color9: #d4605a +! +! Green +*.color2: #edb8ac +*.color10: #d4605a +! +! Yellow +*.color3: #b7ab9b +*.color11: #a86671 +! +! Blue +*.color4: #2e78c2 +*.color12: #7c85c4 +! +! Magenta +*.color5: #c0236f +*.color13: #5c5db2 +! +! Cyan +*.color6: #309186 +*.color14: #819090 +! +! White +*.color7: #eae3ce +*.color15: #fcf4df +! +! Bold, Italic, Underline +*.colorBD: #6b7c7c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/FirefoxDev b/assets/colors/schemes/FirefoxDev new file mode 100644 index 0000000..c082d8f --- /dev/null +++ b/assets/colors/schemes/FirefoxDev @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #7c8fa4 +*.background: #0e1011 +*.cursorColor: #708284 +! +! Black +*.color0: #002831 +*.color8: #001e27 +! +! Red +*.color1: #e63853 +*.color9: #e1003f +! +! Green +*.color2: #5eb83c +*.color10: #1d9000 +! +! Yellow +*.color3: #a57706 +*.color11: #cd9409 +! +! Blue +*.color4: #359ddf +*.color12: #006fc0 +! +! Magenta +*.color5: #d75cff +*.color13: #a200da +! +! Cyan +*.color6: #4b73a2 +*.color14: #005794 +! +! White +*.color7: #dcdcdc +*.color15: #e2e2e2 +! +! Bold, Italic, Underline +*.colorBD: #a7acb2 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Firewatch b/assets/colors/schemes/Firewatch new file mode 100644 index 0000000..d5d44b9 --- /dev/null +++ b/assets/colors/schemes/Firewatch @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #9ba2b2 +*.background: #1e2027 +*.cursorColor: #f6f7ec +! +! Black +*.color0: #585f6d +*.color8: #585f6d +! +! Red +*.color1: #d95360 +*.color9: #d95360 +! +! Green +*.color2: #5ab977 +*.color10: #5ab977 +! +! Yellow +*.color3: #dfb563 +*.color11: #dfb563 +! +! Blue +*.color4: #4d89c4 +*.color12: #4c89c5 +! +! Magenta +*.color5: #d55119 +*.color13: #d55119 +! +! Cyan +*.color6: #44a8b6 +*.color14: #44a8b6 +! +! White +*.color7: #e6e5ff +*.color15: #e6e5ff +! +! Bold, Italic, Underline +*.colorBD: #e6e5ff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/FishTank b/assets/colors/schemes/FishTank new file mode 100644 index 0000000..63f84f3 --- /dev/null +++ b/assets/colors/schemes/FishTank @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ecf0fe +*.background: #232537 +*.cursorColor: #fecd5e +! +! Black +*.color0: #03073c +*.color8: #6c5b30 +! +! Red +*.color1: #c6004a +*.color9: #da4b8a +! +! Green +*.color2: #acf157 +*.color10: #dbffa9 +! +! Yellow +*.color3: #fecd5e +*.color11: #fee6a9 +! +! Blue +*.color4: #525fb8 +*.color12: #b2befa +! +! Magenta +*.color5: #986f82 +*.color13: #fda5cd +! +! Cyan +*.color6: #968763 +*.color14: #a5bd86 +! +! White +*.color7: #ecf0fc +*.color15: #f6ffec +! +! Bold, Italic, Underline +*.colorBD: #f6ffeb +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Flat b/assets/colors/schemes/Flat new file mode 100644 index 0000000..7749f11 --- /dev/null +++ b/assets/colors/schemes/Flat @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #2cc55d +*.background: #002240 +*.cursorColor: #e5be0c +! +! Black +*.color0: #222d3f +*.color8: #212c3c +! +! Red +*.color1: #a82320 +*.color9: #d4312e +! +! Green +*.color2: #32a548 +*.color10: #2d9440 +! +! Yellow +*.color3: #e58d11 +*.color11: #e5be0c +! +! Blue +*.color4: #3167ac +*.color12: #3c7dd2 +! +! Magenta +*.color5: #781aa0 +*.color13: #8230a7 +! +! Cyan +*.color6: #2c9370 +*.color14: #35b387 +! +! White +*.color7: #b0b6ba +*.color15: #e7eced +! +! Bold, Italic, Underline +*.colorBD: #e7eced +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Flatland b/assets/colors/schemes/Flatland new file mode 100644 index 0000000..9386133 --- /dev/null +++ b/assets/colors/schemes/Flatland @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b8dbef +*.background: #1d1f21 +*.cursorColor: #708284 +! +! Black +*.color0: #1d1d19 +*.color8: #1d1d19 +! +! Red +*.color1: #f18339 +*.color9: #d22a24 +! +! Green +*.color2: #9fd364 +*.color10: #a7d42c +! +! Yellow +*.color3: #f4ef6d +*.color11: #ff8949 +! +! Blue +*.color4: #5096be +*.color12: #61b9d0 +! +! Magenta +*.color5: #695abc +*.color13: #695abc +! +! Cyan +*.color6: #d63865 +*.color14: #d63865 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Floraverse b/assets/colors/schemes/Floraverse new file mode 100644 index 0000000..1c8e569 --- /dev/null +++ b/assets/colors/schemes/Floraverse @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dbd1b9 +*.background: #0e0d15 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #08002e +*.color8: #331e4d +! +! Red +*.color1: #64002c +*.color9: #d02063 +! +! Green +*.color2: #5d731a +*.color10: #b4ce59 +! +! Yellow +*.color3: #cd751c +*.color11: #fac357 +! +! Blue +*.color4: #1d6da1 +*.color12: #40a4cf +! +! Magenta +*.color5: #b7077e +*.color13: #f12aae +! +! Cyan +*.color6: #42a38c +*.color14: #62caa8 +! +! White +*.color7: #f3e0b8 +*.color15: #fff5db +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/ForestBlue b/assets/colors/schemes/ForestBlue new file mode 100644 index 0000000..ef0cf1c --- /dev/null +++ b/assets/colors/schemes/ForestBlue @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e2d8cd +*.background: #051519 +*.cursorColor: #9e9ecb +! +! Black +*.color0: #333333 +*.color8: #3d3d3d +! +! Red +*.color1: #f8818e +*.color9: #fb3d66 +! +! Green +*.color2: #92d3a2 +*.color10: #6bb48d +! +! Yellow +*.color3: #1a8e63 +*.color11: #30c85a +! +! Blue +*.color4: #8ed0ce +*.color12: #39a7a2 +! +! Magenta +*.color5: #5e468c +*.color13: #7e62b3 +! +! Cyan +*.color6: #31658c +*.color14: #6096bf +! +! White +*.color7: #e2d8cd +*.color15: #e2d8cd +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/FrontEndDelight b/assets/colors/schemes/FrontEndDelight new file mode 100644 index 0000000..3369633 --- /dev/null +++ b/assets/colors/schemes/FrontEndDelight @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #adadad +*.background: #1b1c1d +*.cursorColor: #cdcdcd +! +! Black +*.color0: #242526 +*.color8: #5fac6d +! +! Red +*.color1: #f8511b +*.color9: #f74319 +! +! Green +*.color2: #565747 +*.color10: #74ec4c +! +! Yellow +*.color3: #fa771d +*.color11: #fdc325 +! +! Blue +*.color4: #2c70b7 +*.color12: #3393ca +! +! Magenta +*.color5: #f02e4f +*.color13: #e75e4f +! +! Cyan +*.color6: #3ca1a6 +*.color14: #4fbce6 +! +! White +*.color7: #adadad +*.color15: #8c735b +! +! Bold, Italic, Underline +*.colorBD: #cdcdcd +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/FunForrest b/assets/colors/schemes/FunForrest new file mode 100644 index 0000000..80c6378 --- /dev/null +++ b/assets/colors/schemes/FunForrest @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dec165 +*.background: #251200 +*.cursorColor: #e5591c +! +! Black +*.color0: #000000 +*.color8: #7f6a55 +! +! Red +*.color1: #d6262b +*.color9: #e55a1c +! +! Green +*.color2: #919c00 +*.color10: #bfc65a +! +! Yellow +*.color3: #be8a13 +*.color11: #ffcb1b +! +! Blue +*.color4: #4699a3 +*.color12: #7cc9cf +! +! Magenta +*.color5: #8d4331 +*.color13: #d26349 +! +! Cyan +*.color6: #da8213 +*.color14: #e6a96b +! +! White +*.color7: #ddc265 +*.color15: #ffeaa3 +! +! Bold, Italic, Underline +*.colorBD: #ffeaa3 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Galaxy b/assets/colors/schemes/Galaxy new file mode 100644 index 0000000..aab3b12 --- /dev/null +++ b/assets/colors/schemes/Galaxy @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #1d2837 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #f9555f +*.color9: #fa8c8f +! +! Green +*.color2: #21b089 +*.color10: #35bb9a +! +! Yellow +*.color3: #fef02a +*.color11: #ffff55 +! +! Blue +*.color4: #589df6 +*.color12: #589df6 +! +! Magenta +*.color5: #944d95 +*.color13: #e75699 +! +! Cyan +*.color6: #1f9ee7 +*.color14: #3979bc +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Github b/assets/colors/schemes/Github new file mode 100644 index 0000000..3c58fdd --- /dev/null +++ b/assets/colors/schemes/Github @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #3e3e3e +*.background: #f4f4f4 +*.cursorColor: #3f3f3f +! +! Black +*.color0: #3e3e3e +*.color8: #666666 +! +! Red +*.color1: #970b16 +*.color9: #de0000 +! +! Green +*.color2: #07962a +*.color10: #87d5a2 +! +! Yellow +*.color3: #f8eec7 +*.color11: #f1d007 +! +! Blue +*.color4: #003e8a +*.color12: #2e6cba +! +! Magenta +*.color5: #e94691 +*.color13: #ffa29f +! +! Cyan +*.color6: #89d1ec +*.color14: #1cfafe +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #c95500 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Glacier b/assets/colors/schemes/Glacier new file mode 100644 index 0000000..48b0755 --- /dev/null +++ b/assets/colors/schemes/Glacier @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #0c1115 +*.cursorColor: #6c6c6c +! +! Black +*.color0: #2e343c +*.color8: #404a55 +! +! Red +*.color1: #bd0f2f +*.color9: #bd0f2f +! +! Green +*.color2: #35a770 +*.color10: #49e998 +! +! Yellow +*.color3: #fb9435 +*.color11: #fddf6e +! +! Blue +*.color4: #1f5872 +*.color12: #2a8bc1 +! +! Magenta +*.color5: #bd2523 +*.color13: #ea4727 +! +! Cyan +*.color6: #778397 +*.color14: #a0b6d3 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Grape b/assets/colors/schemes/Grape new file mode 100644 index 0000000..8974d3f --- /dev/null +++ b/assets/colors/schemes/Grape @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #9f9fa1 +*.background: #171423 +*.cursorColor: #a288f7 +! +! Black +*.color0: #2d283f +*.color8: #59516a +! +! Red +*.color1: #ed2261 +*.color9: #f0729a +! +! Green +*.color2: #1fa91b +*.color10: #53aa5e +! +! Yellow +*.color3: #8ddc20 +*.color11: #b2dc87 +! +! Blue +*.color4: #487df4 +*.color12: #a9bcec +! +! Magenta +*.color5: #8d35c9 +*.color13: #ad81c2 +! +! Cyan +*.color6: #3bdeed +*.color14: #9de3eb +! +! White +*.color7: #9e9ea0 +*.color15: #a288f7 +! +! Bold, Italic, Underline +*.colorBD: #9f87ff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Grass b/assets/colors/schemes/Grass new file mode 100644 index 0000000..bcef0b2 --- /dev/null +++ b/assets/colors/schemes/Grass @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #fff0a5 +*.background: #13773d +*.cursorColor: #8c2800 +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #bb0000 +*.color9: #bb0000 +! +! Green +*.color2: #00bb00 +*.color10: #00bb00 +! +! Yellow +*.color3: #e7b000 +*.color11: #e7b000 +! +! Blue +*.color4: #0000a3 +*.color12: #0000bb +! +! Magenta +*.color5: #950062 +*.color13: #ff55ff +! +! Cyan +*.color6: #00bbbb +*.color14: #55ffff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffb03b +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Gruvbox Dark b/assets/colors/schemes/Gruvbox Dark new file mode 100644 index 0000000..7a859db --- /dev/null +++ b/assets/colors/schemes/Gruvbox Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e6d4a3 +*.background: #1e1e1e +*.cursorColor: #bbbbbb +! +! Black +*.color0: #161819 +*.color8: #7f7061 +! +! Red +*.color1: #f73028 +*.color9: #be0f17 +! +! Green +*.color2: #aab01e +*.color10: #868715 +! +! Yellow +*.color3: #f7b125 +*.color11: #cc881a +! +! Blue +*.color4: #719586 +*.color12: #377375 +! +! Magenta +*.color5: #c77089 +*.color13: #a04b73 +! +! Cyan +*.color6: #7db669 +*.color14: #578e57 +! +! White +*.color7: #faefbb +*.color15: #e6d4a3 +! +! Bold, Italic, Underline +*.colorBD: #978771 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Hardcore b/assets/colors/schemes/Hardcore new file mode 100644 index 0000000..659c0fa --- /dev/null +++ b/assets/colors/schemes/Hardcore @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a0a0a0 +*.background: #121212 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #1b1d1e +*.color8: #505354 +! +! Red +*.color1: #f92672 +*.color9: #ff669d +! +! Green +*.color2: #a6e22e +*.color10: #beed5f +! +! Yellow +*.color3: #fd971f +*.color11: #e6db74 +! +! Blue +*.color4: #66d9ef +*.color12: #66d9ef +! +! Magenta +*.color5: #9e6ffe +*.color13: #9e6ffe +! +! Cyan +*.color6: #5e7175 +*.color14: #a3babf +! +! White +*.color7: #ccccc6 +*.color15: #f8f8f2 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Harper b/assets/colors/schemes/Harper new file mode 100644 index 0000000..1602194 --- /dev/null +++ b/assets/colors/schemes/Harper @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a8a49d +*.background: #010101 +*.cursorColor: #a8a49d +! +! Black +*.color0: #010101 +*.color8: #726e6a +! +! Red +*.color1: #f8b63f +*.color9: #f8b63f +! +! Green +*.color2: #7fb5e1 +*.color10: #7fb5e1 +! +! Yellow +*.color3: #d6da25 +*.color11: #d6da25 +! +! Blue +*.color4: #489e48 +*.color12: #489e48 +! +! Magenta +*.color5: #b296c6 +*.color13: #b296c6 +! +! Cyan +*.color6: #f5bfd7 +*.color14: #f5bfd7 +! +! White +*.color7: #a8a49d +*.color15: #fefbea +! +! Bold, Italic, Underline +*.colorBD: #a8a49d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Highway b/assets/colors/schemes/Highway new file mode 100644 index 0000000..be068a2 --- /dev/null +++ b/assets/colors/schemes/Highway @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ededed +*.background: #222225 +*.cursorColor: #e0d9b9 +! +! Black +*.color0: #000000 +*.color8: #5d504a +! +! Red +*.color1: #d00e18 +*.color9: #f07e18 +! +! Green +*.color2: #138034 +*.color10: #b1d130 +! +! Yellow +*.color3: #ffcb3e +*.color11: #fff120 +! +! Blue +*.color4: #006bb3 +*.color12: #4fc2fd +! +! Magenta +*.color5: #6b2775 +*.color13: #de0071 +! +! Cyan +*.color6: #384564 +*.color14: #5d504a +! +! White +*.color7: #ededed +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #fff8d8 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Hipster Green b/assets/colors/schemes/Hipster Green new file mode 100644 index 0000000..503d664 --- /dev/null +++ b/assets/colors/schemes/Hipster Green @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #84c138 +*.background: #100b05 +*.cursorColor: #23ff18 +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #b6214a +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #86a93e +! +! Yellow +*.color3: #bfbf00 +*.color11: #e5e500 +! +! Blue +*.color4: #246eb2 +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #00db00 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Homebrew b/assets/colors/schemes/Homebrew new file mode 100644 index 0000000..d63beec --- /dev/null +++ b/assets/colors/schemes/Homebrew @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #00ff00 +*.background: #000000 +*.cursorColor: #23ff18 +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #990000 +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #00d900 +! +! Yellow +*.color3: #999900 +*.color11: #e5e500 +! +! Blue +*.color4: #0000b2 +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #00ff00 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Hurtado b/assets/colors/schemes/Hurtado new file mode 100644 index 0000000..7bc7d2d --- /dev/null +++ b/assets/colors/schemes/Hurtado @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dbdbdb +*.background: #000000 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #575757 +*.color8: #262626 +! +! Red +*.color1: #ff1b00 +*.color9: #d51d00 +! +! Green +*.color2: #a5e055 +*.color10: #a5df55 +! +! Yellow +*.color3: #fbe74a +*.color11: #fbe84a +! +! Blue +*.color4: #496487 +*.color12: #89beff +! +! Magenta +*.color5: #fd5ff1 +*.color13: #c001c1 +! +! Cyan +*.color6: #86e9fe +*.color14: #86eafe +! +! White +*.color7: #cbcccb +*.color15: #dbdbdb +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Hybrid b/assets/colors/schemes/Hybrid new file mode 100644 index 0000000..56d800d --- /dev/null +++ b/assets/colors/schemes/Hybrid @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b7bcba +*.background: #161719 +*.cursorColor: #b7bcba +! +! Black +*.color0: #2a2e33 +*.color8: #1d1f22 +! +! Red +*.color1: #b84d51 +*.color9: #8d2e32 +! +! Green +*.color2: #b3bf5a +*.color10: #798431 +! +! Yellow +*.color3: #e4b55e +*.color11: #e58a50 +! +! Blue +*.color4: #6e90b0 +*.color12: #4b6b88 +! +! Magenta +*.color5: #a17eac +*.color13: #6e5079 +! +! Cyan +*.color6: #7fbfb4 +*.color14: #4d7b74 +! +! White +*.color7: #b5b9b6 +*.color15: #5a626a +! +! Bold, Italic, Underline +*.colorBD: #b7bcba +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/IC_Green_PPL b/assets/colors/schemes/IC_Green_PPL new file mode 100644 index 0000000..b248c8f --- /dev/null +++ b/assets/colors/schemes/IC_Green_PPL @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d9efd3 +*.background: #3a3d3f +*.cursorColor: #42ff58 +! +! Black +*.color0: #1f1f1f +*.color8: #032710 +! +! Red +*.color1: #fb002a +*.color9: #a7ff3f +! +! Green +*.color2: #339c24 +*.color10: #9fff6d +! +! Yellow +*.color3: #659b25 +*.color11: #d2ff6d +! +! Blue +*.color4: #149b45 +*.color12: #72ffb5 +! +! Magenta +*.color5: #53b82c +*.color13: #50ff3e +! +! Cyan +*.color6: #2cb868 +*.color14: #22ff71 +! +! White +*.color7: #e0ffef +*.color15: #daefd0 +! +! Bold, Italic, Underline +*.colorBD: #9fff6d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/IC_Orange_PPL b/assets/colors/schemes/IC_Orange_PPL new file mode 100644 index 0000000..d623332 --- /dev/null +++ b/assets/colors/schemes/IC_Orange_PPL @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffcb83 +*.background: #262626 +*.cursorColor: #fc531d +! +! Black +*.color0: #000000 +*.color8: #6a4f2a +! +! Red +*.color1: #c13900 +*.color9: #ff8c68 +! +! Green +*.color2: #a4a900 +*.color10: #f6ff40 +! +! Yellow +*.color3: #caaf00 +*.color11: #ffe36e +! +! Blue +*.color4: #bd6d00 +*.color12: #ffbe55 +! +! Magenta +*.color5: #fc5e00 +*.color13: #fc874f +! +! Cyan +*.color6: #f79500 +*.color14: #c69752 +! +! White +*.color7: #ffc88a +*.color15: #fafaff +! +! Bold, Italic, Underline +*.colorBD: #fafaff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/IR_Black b/assets/colors/schemes/IR_Black new file mode 100644 index 0000000..8548020 --- /dev/null +++ b/assets/colors/schemes/IR_Black @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f1f1f1 +*.background: #000000 +*.cursorColor: #808080 +! +! Black +*.color0: #4f4f4f +*.color8: #7b7b7b +! +! Red +*.color1: #fa6c60 +*.color9: #fcb6b0 +! +! Green +*.color2: #a8ff60 +*.color10: #cfffab +! +! Yellow +*.color3: #fffeb7 +*.color11: #ffffcc +! +! Blue +*.color4: #96cafe +*.color12: #b5dcff +! +! Magenta +*.color5: #fa73fd +*.color13: #fb9cfe +! +! Cyan +*.color6: #c6c5fe +*.color14: #e0e0fe +! +! White +*.color7: #efedef +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Iceberg b/assets/colors/schemes/Iceberg new file mode 100644 index 0000000..b165d5c --- /dev/null +++ b/assets/colors/schemes/Iceberg @@ -0,0 +1,42 @@ +! Iceberg +! https://cocopon.github.io/iceberg.vim/ +*.foreground: #c6c8d1 +*.background: #161821 +*.cursorColor: #c6c8d1 +! +! Black +*.color0: #1e2132 +*.color8: #6b7089 +! +! Red +*.color1: #e27878 +*.color9: #e98989 +! +! Green +*.color2: #b4be82 +*.color10: #c0ca8e +! +! Yellow +*.color3: #e2a478 +*.color11: #e9b189 +! +! Blue +*.color4: #84a0c6 +*.color12: #91acd1 +! +! Magenta +*.color5: #a093c7 +*.color13: #ada0d3 +! +! Cyan +*.color6: #89b8c2 +*.color14: #95c4ce +! +! White +*.color7: #c6c8d1 +*.color15: #d2d4de +! +! Bold, Italic, Underline +*.colorBD: #c6c8d1 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Jackie Brown b/assets/colors/schemes/Jackie Brown new file mode 100644 index 0000000..b65caee --- /dev/null +++ b/assets/colors/schemes/Jackie Brown @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffcc2f +*.background: #2c1d16 +*.cursorColor: #23ff18 +! +! Black +*.color0: #2c1d16 +*.color8: #666666 +! +! Red +*.color1: #ef5734 +*.color9: #e50000 +! +! Green +*.color2: #2baf2b +*.color10: #86a93e +! +! Yellow +*.color3: #bebf00 +*.color11: #e5e500 +! +! Blue +*.color4: #246eb2 +*.color12: #0000ff +! +! Magenta +*.color5: #d05ec1 +*.color13: #e500e5 +! +! Cyan +*.color6: #00acee +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #ffcc2f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Japanesque b/assets/colors/schemes/Japanesque new file mode 100644 index 0000000..7f6de65 --- /dev/null +++ b/assets/colors/schemes/Japanesque @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f7f6ec +*.background: #1e1e1e +*.cursorColor: #edcf4f +! +! Black +*.color0: #343935 +*.color8: #595b59 +! +! Red +*.color1: #cf3f61 +*.color9: #d18fa6 +! +! Green +*.color2: #7bb75b +*.color10: #767f2c +! +! Yellow +*.color3: #e9b32a +*.color11: #78592f +! +! Blue +*.color4: #4c9ad4 +*.color12: #135979 +! +! Magenta +*.color5: #a57fc4 +*.color13: #604291 +! +! Cyan +*.color6: #389aad +*.color14: #76bbca +! +! White +*.color7: #fafaf6 +*.color15: #b2b5ae +! +! Bold, Italic, Underline +*.colorBD: #fffffa +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Jazz b/assets/colors/schemes/Jazz new file mode 100644 index 0000000..3b57292 --- /dev/null +++ b/assets/colors/schemes/Jazz @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xresources.py +! +*.foreground: #3f3f3f +*.background: #f3f2f1 +*.cursorColor: #9acf9f +! +! Black +*.color0: #282c34 +*.color8: #548962 +! +! Red +*.color1: #e06c75 +*.color9: #d19a66 +! +! Green +*.color2: #668e3d +*.color10: #668e3d +! +! Yellow +*.color3: #c49041 +*.color11: #c49041 +! +! Blue +*.color4: #8c71bf +*.color12: #8c71bf +! +! Magenta +*.color5: #c678dd +*.color13: #c678dd +! +! Cyan +*.color6: #878b91 +*.color14: #5e6091 +! +! White +*.color7: #abb2bf +*.color15: #f2f7ff +! +! Bold, Italic, Underline +*.colorBD: #33374c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Jellybeans b/assets/colors/schemes/Jellybeans new file mode 100644 index 0000000..308202d --- /dev/null +++ b/assets/colors/schemes/Jellybeans @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dedede +*.background: #121212 +*.cursorColor: #ffa560 +! +! Black +*.color0: #929292 +*.color8: #bdbdbd +! +! Red +*.color1: #e27373 +*.color9: #ffa1a1 +! +! Green +*.color2: #94b979 +*.color10: #bddeab +! +! Yellow +*.color3: #ffba7b +*.color11: #ffdca0 +! +! Blue +*.color4: #97bedc +*.color12: #b1d8f6 +! +! Magenta +*.color5: #e1c0fa +*.color13: #fbdaff +! +! Cyan +*.color6: #00988e +*.color14: #1ab2a8 +! +! White +*.color7: #dedede +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/JetBrains Darcula b/assets/colors/schemes/JetBrains Darcula new file mode 100644 index 0000000..d7643d6 --- /dev/null +++ b/assets/colors/schemes/JetBrains Darcula @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #adadad +*.background: #202020 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #fa5355 +*.color9: #fb7172 +! +! Green +*.color2: #126e00 +*.color10: #67ff4f +! +! Yellow +*.color3: #c2c300 +*.color11: #ffff00 +! +! Blue +*.color4: #4581eb +*.color12: #6d9df1 +! +! Magenta +*.color5: #fa54ff +*.color13: #fb82ff +! +! Cyan +*.color6: #33c2c1 +*.color14: #60d3d1 +! +! White +*.color7: #adadad +*.color15: #eeeeee +! +! Bold, Italic, Underline +*.colorBD: #eeeeee +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Kibble b/assets/colors/schemes/Kibble new file mode 100644 index 0000000..0b38a75 --- /dev/null +++ b/assets/colors/schemes/Kibble @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f7f7f7 +*.background: #0e100a +*.cursorColor: #9fda9c +! +! Black +*.color0: #4d4d4d +*.color8: #5a5a5a +! +! Red +*.color1: #c70031 +*.color9: #f01578 +! +! Green +*.color2: #29cf13 +*.color10: #6ce05c +! +! Yellow +*.color3: #d8e30e +*.color11: #f3f79e +! +! Blue +*.color4: #3449d1 +*.color12: #97a4f7 +! +! Magenta +*.color5: #8400ff +*.color13: #c495f0 +! +! Cyan +*.color6: #0798ab +*.color14: #68f2e0 +! +! White +*.color7: #e2d1e3 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ca631e +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Later This Evening b/assets/colors/schemes/Later This Evening new file mode 100644 index 0000000..69128de --- /dev/null +++ b/assets/colors/schemes/Later This Evening @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #959595 +*.background: #222222 +*.cursorColor: #424242 +! +! Black +*.color0: #2b2b2b +*.color8: #454747 +! +! Red +*.color1: #d45a60 +*.color9: #d3232f +! +! Green +*.color2: #afba67 +*.color10: #aabb39 +! +! Yellow +*.color3: #e5d289 +*.color11: #e5be39 +! +! Blue +*.color4: #a0bad6 +*.color12: #6699d6 +! +! Magenta +*.color5: #c092d6 +*.color13: #ab53d6 +! +! Cyan +*.color6: #91bfb7 +*.color14: #5fc0ae +! +! White +*.color7: #3c3d3d +*.color15: #c1c2c2 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Lavandula b/assets/colors/schemes/Lavandula new file mode 100644 index 0000000..78af686 --- /dev/null +++ b/assets/colors/schemes/Lavandula @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #736e7d +*.background: #050014 +*.cursorColor: #8c91fa +! +! Black +*.color0: #230046 +*.color8: #372d46 +! +! Red +*.color1: #7d1625 +*.color9: #e05167 +! +! Green +*.color2: #337e6f +*.color10: #52e0c4 +! +! Yellow +*.color3: #7f6f49 +*.color11: #e0c386 +! +! Blue +*.color4: #4f4a7f +*.color12: #8e87e0 +! +! Magenta +*.color5: #5a3f7f +*.color13: #a776e0 +! +! Cyan +*.color6: #58777f +*.color14: #9ad4e0 +! +! White +*.color7: #736e7d +*.color15: #8c91fa +! +! Bold, Italic, Underline +*.colorBD: #8c91fa +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Light Owl b/assets/colors/schemes/Light Owl new file mode 100644 index 0000000..24b01c0 --- /dev/null +++ b/assets/colors/schemes/Light Owl @@ -0,0 +1,44 @@ +! +! Light Owl +! https://github.com/sdras/night-owl-vscode-theme +! +*.foreground: #403f53 +*.background: #fbfbfb +*.cursorColor: #90a7b2 +! +! Black +*.color0: #403f53 +*.color8: #403f53 +! +! Red +*.color1: #de3d3b +*.color9: #de3d3b +! +! Green +*.color2: #08916a +*.color10: #08916a +! +! Yellow +*.color3: #e0af02 +*.color11: #daaa01 +! +! Blue +*.color4: #288ed7 +*.color12: #288ed7 +! +! Magenta +*.color5: #d6438a +*.color13: #d6438a +! +! Cyan +*.color6: #2aa298 +*.color14: #2aa298 +! +! White +*.color7: #f0f0f0 +*.color15: #979797 +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/LiquidCarbon b/assets/colors/schemes/LiquidCarbon new file mode 100644 index 0000000..4b019ec --- /dev/null +++ b/assets/colors/schemes/LiquidCarbon @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #afc2c2 +*.background: #303030 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #ff3030 +*.color9: #ff3030 +! +! Green +*.color2: #559a70 +*.color10: #559a70 +! +! Yellow +*.color3: #ccac00 +*.color11: #ccac00 +! +! Blue +*.color4: #0099cc +*.color12: #0099cc +! +! Magenta +*.color5: #cc69c8 +*.color13: #cc69c8 +! +! Cyan +*.color6: #7ac4cc +*.color14: #7ac4cc +! +! White +*.color7: #bccccc +*.color15: #bccccc +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/LiquidCarbonTransparent b/assets/colors/schemes/LiquidCarbonTransparent new file mode 100644 index 0000000..a2aaa43 --- /dev/null +++ b/assets/colors/schemes/LiquidCarbonTransparent @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #afc2c2 +*.background: #000000 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #ff3030 +*.color9: #ff3030 +! +! Green +*.color2: #559a70 +*.color10: #559a70 +! +! Yellow +*.color3: #ccac00 +*.color11: #ccac00 +! +! Blue +*.color4: #0099cc +*.color12: #0099cc +! +! Magenta +*.color5: #cc69c8 +*.color13: #cc69c8 +! +! Cyan +*.color6: #7ac4cc +*.color14: #7ac4cc +! +! White +*.color7: #bccccc +*.color15: #bccccc +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/LiquidCarbonTransparentInverse b/assets/colors/schemes/LiquidCarbonTransparentInverse new file mode 100644 index 0000000..ce0985a --- /dev/null +++ b/assets/colors/schemes/LiquidCarbonTransparentInverse @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #afc2c2 +*.background: #000000 +*.cursorColor: #ffffff +! +! Black +*.color0: #bccccd +*.color8: #ffffff +! +! Red +*.color1: #ff3030 +*.color9: #ff3030 +! +! Green +*.color2: #559a70 +*.color10: #559a70 +! +! Yellow +*.color3: #ccac00 +*.color11: #ccac00 +! +! Blue +*.color4: #0099cc +*.color12: #0099cc +! +! Magenta +*.color5: #cc69c8 +*.color13: #cc69c8 +! +! Cyan +*.color6: #7ac4cc +*.color14: #7ac4cc +! +! White +*.color7: #000000 +*.color15: #000000 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Man Page b/assets/colors/schemes/Man Page new file mode 100644 index 0000000..d7b2b37 --- /dev/null +++ b/assets/colors/schemes/Man Page @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #000000 +*.background: #fef49c +*.cursorColor: #7f7f7f +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #cc0000 +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #00d900 +! +! Yellow +*.color3: #999900 +*.color11: #e5e500 +! +! Blue +*.color4: #0000b2 +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #cccccc +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #000000 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Material b/assets/colors/schemes/Material new file mode 100644 index 0000000..cea2b54 --- /dev/null +++ b/assets/colors/schemes/Material @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #232322 +*.background: #eaeaea +*.cursorColor: #16afca +! +! Black +*.color0: #212121 +*.color8: #424242 +! +! Red +*.color1: #b7141f +*.color9: #e83b3f +! +! Green +*.color2: #457b24 +*.color10: #7aba3a +! +! Yellow +*.color3: #f6981e +*.color11: #ffea2e +! +! Blue +*.color4: #134eb2 +*.color12: #54a4f3 +! +! Magenta +*.color5: #560088 +*.color13: #aa4dbc +! +! Cyan +*.color6: #0e717c +*.color14: #26bbd1 +! +! White +*.color7: #efefef +*.color15: #d9d9d9 +! +! Bold, Italic, Underline +*.colorBD: #b7141f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/MaterialDark b/assets/colors/schemes/MaterialDark new file mode 100644 index 0000000..7089881 --- /dev/null +++ b/assets/colors/schemes/MaterialDark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e5e5e5 +*.background: #232322 +*.cursorColor: #16afca +! +! Black +*.color0: #212121 +*.color8: #424242 +! +! Red +*.color1: #b7141f +*.color9: #e83b3f +! +! Green +*.color2: #457b24 +*.color10: #7aba3a +! +! Yellow +*.color3: #f6981e +*.color11: #ffea2e +! +! Blue +*.color4: #134eb2 +*.color12: #54a4f3 +! +! Magenta +*.color5: #560088 +*.color13: #aa4dbc +! +! Cyan +*.color6: #0e717c +*.color14: #26bbd1 +! +! White +*.color7: #efefef +*.color15: #d9d9d9 +! +! Bold, Italic, Underline +*.colorBD: #b7141f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Mathias b/assets/colors/schemes/Mathias new file mode 100644 index 0000000..3063251 --- /dev/null +++ b/assets/colors/schemes/Mathias @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bbbbbb +*.background: #000000 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #e52222 +*.color9: #ff5555 +! +! Green +*.color2: #a6e32d +*.color10: #55ff55 +! +! Yellow +*.color3: #fc951e +*.color11: #ffff55 +! +! Blue +*.color4: #c48dff +*.color12: #5555ff +! +! Magenta +*.color5: #fa2573 +*.color13: #ff55ff +! +! Cyan +*.color6: #67d9f0 +*.color14: #55ffff +! +! White +*.color7: #f2f2f2 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Medallion b/assets/colors/schemes/Medallion new file mode 100644 index 0000000..0719679 --- /dev/null +++ b/assets/colors/schemes/Medallion @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #cac296 +*.background: #1d1908 +*.cursorColor: #d3ba30 +! +! Black +*.color0: #000000 +*.color8: #5e5219 +! +! Red +*.color1: #b64c00 +*.color9: #ff9149 +! +! Green +*.color2: #7c8b16 +*.color10: #b2ca3b +! +! Yellow +*.color3: #d3bd26 +*.color11: #ffe54a +! +! Blue +*.color4: #616bb0 +*.color12: #acb8ff +! +! Magenta +*.color5: #8c5a90 +*.color13: #ffa0ff +! +! Cyan +*.color6: #916c25 +*.color14: #ffbc51 +! +! White +*.color7: #cac29a +*.color15: #fed698 +! +! Bold, Italic, Underline +*.colorBD: #ffd890 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Melange Dark b/assets/colors/schemes/Melange Dark new file mode 100644 index 0000000..f65dbc6 --- /dev/null +++ b/assets/colors/schemes/Melange Dark @@ -0,0 +1,44 @@ +! +! Melange Dark +! https://github.com/savq/melange +! +*.foreground: #ece1d7 +*.background: #2a2520 +*.cursorColor: #ece1d7 +! +! Black +*.color0: #352f2a +*.color8: #4d453e +! +! Red +*.color1 #b65c60 +*.color9 #f17c64 +! +! Green +*.color2 #78997a +*.color10 #99d59d +! +! Yellow +*.color3 #ebc06d +*.color11 #ebc06d +! +! Blue +*.color4 #9aacce +*.color12 #9aacce +! +! Magenta +*.color5 #b380b0 +*.color13 #ce9bcb +! +! Cyan +*.color6 #86a3a3 +*.color14 #88b3b2 +! +! White +*.color7 #a38d78 +*.color15 #c1a78e +! +! Bold, Italic, Underline +*.colorBD: #fff4ea +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Misterioso b/assets/colors/schemes/Misterioso new file mode 100644 index 0000000..4cf8d05 --- /dev/null +++ b/assets/colors/schemes/Misterioso @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e1e1e0 +*.background: #2d3743 +*.cursorColor: #000000 +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #ff4242 +*.color9: #ff3242 +! +! Green +*.color2: #74af68 +*.color10: #74cd68 +! +! Yellow +*.color3: #ffad29 +*.color11: #ffb929 +! +! Blue +*.color4: #338f86 +*.color12: #23d7d7 +! +! Magenta +*.color5: #9414e6 +*.color13: #ff37ff +! +! Cyan +*.color6: #23d7d7 +*.color14: #00ede1 +! +! White +*.color7: #e1e1e0 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #000000 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Molokai b/assets/colors/schemes/Molokai new file mode 100644 index 0000000..17b254a --- /dev/null +++ b/assets/colors/schemes/Molokai @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bbbbbb +*.background: #121212 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #121212 +*.color8: #555555 +! +! Red +*.color1: #fa2573 +*.color9: #f6669d +! +! Green +*.color2: #98e123 +*.color10: #b1e05f +! +! Yellow +*.color3: #dfd460 +*.color11: #fff26d +! +! Blue +*.color4: #1080d0 +*.color12: #00afff +! +! Magenta +*.color5: #8700ff +*.color13: #af87ff +! +! Cyan +*.color6: #43a8d0 +*.color14: #51ceff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/MonaLisa b/assets/colors/schemes/MonaLisa new file mode 100644 index 0000000..a827fec --- /dev/null +++ b/assets/colors/schemes/MonaLisa @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f7d66a +*.background: #120b0d +*.cursorColor: #c46c32 +! +! Black +*.color0: #351b0e +*.color8: #874228 +! +! Red +*.color1: #9b291c +*.color9: #ff4331 +! +! Green +*.color2: #636232 +*.color10: #b4b264 +! +! Yellow +*.color3: #c36e28 +*.color11: #ff9566 +! +! Blue +*.color4: #515c5d +*.color12: #9eb2b4 +! +! Magenta +*.color5: #9b1d29 +*.color13: #ff5b6a +! +! Cyan +*.color6: #588056 +*.color14: #8acd8f +! +! White +*.color7: #f7d75c +*.color15: #ffe598 +! +! Bold, Italic, Underline +*.colorBD: #fee4a0 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Monokai Soda b/assets/colors/schemes/Monokai Soda new file mode 100644 index 0000000..73b007c --- /dev/null +++ b/assets/colors/schemes/Monokai Soda @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c4c5b5 +*.background: #1a1a1a +*.cursorColor: #f6f7ec +! +! Black +*.color0: #1a1a1a +*.color8: #625e4c +! +! Red +*.color1: #f4005f +*.color9: #f4005f +! +! Green +*.color2: #98e024 +*.color10: #98e024 +! +! Yellow +*.color3: #fa8419 +*.color11: #e0d561 +! +! Blue +*.color4: #9d65ff +*.color12: #9d65ff +! +! Magenta +*.color5: #f4005f +*.color13: #f4005f +! +! Cyan +*.color6: #58d1eb +*.color14: #58d1eb +! +! White +*.color7: #c4c5b5 +*.color15: #f6f6ef +! +! Bold, Italic, Underline +*.colorBD: #c4c5b5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Monokai Vivid b/assets/colors/schemes/Monokai Vivid new file mode 100644 index 0000000..5369a8e --- /dev/null +++ b/assets/colors/schemes/Monokai Vivid @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f9f9f9 +*.background: #121212 +*.cursorColor: #fb0007 +! +! Black +*.color0: #121212 +*.color8: #838383 +! +! Red +*.color1: #fa2934 +*.color9: #f6669d +! +! Green +*.color2: #98e123 +*.color10: #b1e05f +! +! Yellow +*.color3: #fff30a +*.color11: #fff26d +! +! Blue +*.color4: #0443ff +*.color12: #0443ff +! +! Magenta +*.color5: #f800f8 +*.color13: #f200f6 +! +! Cyan +*.color6: #01b6ed +*.color14: #51ceff +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/N0tch2k b/assets/colors/schemes/N0tch2k new file mode 100644 index 0000000..6c44863 --- /dev/null +++ b/assets/colors/schemes/N0tch2k @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a0a0a0 +*.background: #222222 +*.cursorColor: #aa9175 +! +! Black +*.color0: #383838 +*.color8: #474747 +! +! Red +*.color1: #a95551 +*.color9: #a97775 +! +! Green +*.color2: #666666 +*.color10: #8c8c8c +! +! Yellow +*.color3: #a98051 +*.color11: #a99175 +! +! Blue +*.color4: #657d3e +*.color12: #98bd5e +! +! Magenta +*.color5: #767676 +*.color13: #a3a3a3 +! +! Cyan +*.color6: #c9c9c9 +*.color14: #dcdcdc +! +! White +*.color7: #d0b8a3 +*.color15: #d8c8bb +! +! Bold, Italic, Underline +*.colorBD: #e5e5e5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Neopolitan b/assets/colors/schemes/Neopolitan new file mode 100644 index 0000000..7194e14 --- /dev/null +++ b/assets/colors/schemes/Neopolitan @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #271f19 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #800000 +*.color9: #800000 +! +! Green +*.color2: #61ce3c +*.color10: #61ce3c +! +! Yellow +*.color3: #fbde2d +*.color11: #fbde2d +! +! Blue +*.color4: #253b76 +*.color12: #253b76 +! +! Magenta +*.color5: #ff0080 +*.color13: #ff0080 +! +! Cyan +*.color6: #8da6ce +*.color14: #8da6ce +! +! White +*.color7: #f8f8f8 +*.color15: #f8f8f8 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Neutron b/assets/colors/schemes/Neutron new file mode 100644 index 0000000..8a9adcb --- /dev/null +++ b/assets/colors/schemes/Neutron @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e6e8ef +*.background: #1c1e22 +*.cursorColor: #f6f7ec +! +! Black +*.color0: #23252b +*.color8: #23252b +! +! Red +*.color1: #b54036 +*.color9: #b54036 +! +! Green +*.color2: #5ab977 +*.color10: #5ab977 +! +! Yellow +*.color3: #deb566 +*.color11: #deb566 +! +! Blue +*.color4: #6a7c93 +*.color12: #6a7c93 +! +! Magenta +*.color5: #a4799d +*.color13: #a4799d +! +! Cyan +*.color6: #3f94a8 +*.color14: #3f94a8 +! +! White +*.color7: #e6e8ef +*.color15: #ebedf2 +! +! Bold, Italic, Underline +*.colorBD: #52606b +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Night Owl b/assets/colors/schemes/Night Owl new file mode 100644 index 0000000..65a1793 --- /dev/null +++ b/assets/colors/schemes/Night Owl @@ -0,0 +1,44 @@ +! +! Night Owl +! https://github.com/sdras/night-owl-vscode-theme +! +*.foreground: #d6deeb +*.background: #011627 +*.cursorColor: #80a4c2 +! +! Black +*.color0: #011627 +*.color8: #969696 +! +! Red +*.color1: #ef5350 +*.color9: #ef5350 +! +! Green +*.color2: #22da6e +*.color10: #22da6e +! +! Yellow +*.color3: #addb67 +*.color11: #ffeb95 +! +! Blue +*.color4: #82aaff +*.color12: #82aaff +! +! Magenta +*.color5: #c792ea +*.color13: #c792ea +! +! Cyan +*.color6: #21c7a8 +*.color14: #7fdbca +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/NightLion v1 b/assets/colors/schemes/NightLion v1 new file mode 100644 index 0000000..d836ce2 --- /dev/null +++ b/assets/colors/schemes/NightLion v1 @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bbbbbb +*.background: #000000 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #4c4c4c +*.color8: #555555 +! +! Red +*.color1: #bb0000 +*.color9: #ff5555 +! +! Green +*.color2: #5fde8f +*.color10: #55ff55 +! +! Yellow +*.color3: #f3f167 +*.color11: #ffff55 +! +! Blue +*.color4: #276bd8 +*.color12: #5555ff +! +! Magenta +*.color5: #bb00bb +*.color13: #ff55ff +! +! Cyan +*.color6: #00dadf +*.color14: #55ffff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #e3e3e3 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/NightLion v2 b/assets/colors/schemes/NightLion v2 new file mode 100644 index 0000000..1a77ff7 --- /dev/null +++ b/assets/colors/schemes/NightLion v2 @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bbbbbb +*.background: #171717 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #4c4c4c +*.color8: #555555 +! +! Red +*.color1: #bb0000 +*.color9: #ff5555 +! +! Green +*.color2: #04f623 +*.color10: #7df71d +! +! Yellow +*.color3: #f3f167 +*.color11: #ffff55 +! +! Blue +*.color4: #64d0f0 +*.color12: #62cbe8 +! +! Magenta +*.color5: #ce6fdb +*.color13: #ff9bf5 +! +! Cyan +*.color6: #00dadf +*.color14: #00ccd8 +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #e3e3e3 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Nord b/assets/colors/schemes/Nord new file mode 100644 index 0000000..47f02d9 --- /dev/null +++ b/assets/colors/schemes/Nord @@ -0,0 +1,42 @@ +! +! +*.foreground: #d8dee9 +*.background: #2e3440 +*.cursorColor: #d8dee9 +! +! Black +*.color0: #3b4252 +*.color8: #373e4d +! +! Red +*.color1: #bf616a +*.color9: #94545d +! +! Green +*.color2: #a3be8c +*.color10: #809575 +! +! Yellow +*.color3: #ebcb8b +*.color11: #b29e75 +! +! Blue +*.color4: #81a1c1 +*.color12: #68809a +! +! Magenta +*.color5: #b48ead +*.color13: #8c738c +! +! Cyan +*.color6: #88c0d0 +*.color14: #6d96a5 +! +! White +*.color7: #e5e9f0 +*.color15: #aeb3bb +! +! Bold, Italic, Underline +*.colorBD: #a5abb6 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Novel b/assets/colors/schemes/Novel new file mode 100644 index 0000000..94fabb4 --- /dev/null +++ b/assets/colors/schemes/Novel @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #3b2322 +*.background: #dfdbc3 +*.cursorColor: #73635a +! +! Black +*.color0: #000000 +*.color8: #808080 +! +! Red +*.color1: #cc0000 +*.color9: #cc0000 +! +! Green +*.color2: #009600 +*.color10: #009600 +! +! Yellow +*.color3: #d06b00 +*.color11: #d06b00 +! +! Blue +*.color4: #0000cc +*.color12: #0000cc +! +! Magenta +*.color5: #cc00cc +*.color13: #cc00cc +! +! Cyan +*.color6: #0087cc +*.color14: #0087cc +! +! White +*.color7: #cccccc +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #8e2a19 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Obsidian b/assets/colors/schemes/Obsidian new file mode 100644 index 0000000..5f5751d --- /dev/null +++ b/assets/colors/schemes/Obsidian @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #cdcdcd +*.background: #283033 +*.cursorColor: #c0cad0 +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #a60001 +*.color9: #ff0003 +! +! Green +*.color2: #00bb00 +*.color10: #93c863 +! +! Yellow +*.color3: #fecd22 +*.color11: #fef874 +! +! Blue +*.color4: #3a9bdb +*.color12: #a1d7ff +! +! Magenta +*.color5: #bb00bb +*.color13: #ff55ff +! +! Cyan +*.color6: #00bbbb +*.color14: #55ffff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Ocean b/assets/colors/schemes/Ocean new file mode 100644 index 0000000..13fe770 --- /dev/null +++ b/assets/colors/schemes/Ocean @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #224fbc +*.cursorColor: #7f7f7f +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #990000 +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #00d900 +! +! Yellow +*.color3: #999900 +*.color11: #e5e500 +! +! Blue +*.color4: #0000b2 +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/OceanicMaterial b/assets/colors/schemes/OceanicMaterial new file mode 100644 index 0000000..b5e9422 --- /dev/null +++ b/assets/colors/schemes/OceanicMaterial @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c2c8d7 +*.background: #1c262b +*.cursorColor: #b3b8c3 +! +! Black +*.color0: #000000 +*.color8: #777777 +! +! Red +*.color1: #ee2b2a +*.color9: #dc5c60 +! +! Green +*.color2: #40a33f +*.color10: #70be71 +! +! Yellow +*.color3: #ffea2e +*.color11: #fff163 +! +! Blue +*.color4: #1e80f0 +*.color12: #54a4f3 +! +! Magenta +*.color5: #8800a0 +*.color13: #aa4dbc +! +! Cyan +*.color6: #16afca +*.color14: #42c7da +! +! White +*.color7: #a4a4a4 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Ollie b/assets/colors/schemes/Ollie new file mode 100644 index 0000000..89409ef --- /dev/null +++ b/assets/colors/schemes/Ollie @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #8a8dae +*.background: #222125 +*.cursorColor: #5b6ea7 +! +! Black +*.color0: #000000 +*.color8: #5b3725 +! +! Red +*.color1: #ac2e31 +*.color9: #ff3d48 +! +! Green +*.color2: #31ac61 +*.color10: #3bff99 +! +! Yellow +*.color3: #ac4300 +*.color11: #ff5e1e +! +! Blue +*.color4: #2d57ac +*.color12: #4488ff +! +! Magenta +*.color5: #b08528 +*.color13: #ffc21d +! +! Cyan +*.color6: #1fa6ac +*.color14: #1ffaff +! +! White +*.color7: #8a8eac +*.color15: #5b6ea7 +! +! Bold, Italic, Underline +*.colorBD: #5c6dac +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/OneHalfDark b/assets/colors/schemes/OneHalfDark new file mode 100644 index 0000000..2d70063 --- /dev/null +++ b/assets/colors/schemes/OneHalfDark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dcdfe4 +*.background: #282c34 +*.cursorColor: #a3b3cc +! +! Black +*.color0: #282c34 +*.color8: #282c34 +! +! Red +*.color1: #e06c75 +*.color9: #e06c75 +! +! Green +*.color2: #98c379 +*.color10: #98c379 +! +! Yellow +*.color3: #e5c07b +*.color11: #e5c07b +! +! Blue +*.color4: #61afef +*.color12: #61afef +! +! Magenta +*.color5: #c678dd +*.color13: #c678dd +! +! Cyan +*.color6: #56b6c2 +*.color14: #56b6c2 +! +! White +*.color7: #dcdfe4 +*.color15: #dcdfe4 +! +! Bold, Italic, Underline +*.colorBD: #abb2bf +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/OneHalfLight b/assets/colors/schemes/OneHalfLight new file mode 100644 index 0000000..558a872 --- /dev/null +++ b/assets/colors/schemes/OneHalfLight @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #383a42 +*.background: #fafafa +*.cursorColor: #bfceff +! +! Black +*.color0: #383a42 +*.color8: #4f525e +! +! Red +*.color1: #e45649 +*.color9: #e06c75 +! +! Green +*.color2: #50a14f +*.color10: #98c379 +! +! Yellow +*.color3: #c18401 +*.color11: #e5c07b +! +! Blue +*.color4: #0184bc +*.color12: #61afef +! +! Magenta +*.color5: #a626a4 +*.color13: #c678dd +! +! Cyan +*.color6: #0997b3 +*.color14: #56b6c2 +! +! White +*.color7: #fafafa +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #abb2bf +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Pandora b/assets/colors/schemes/Pandora new file mode 100644 index 0000000..e0889d4 --- /dev/null +++ b/assets/colors/schemes/Pandora @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e1e1e1 +*.background: #141e43 +*.cursorColor: #43d58e +! +! Black +*.color0: #000000 +*.color8: #3f5648 +! +! Red +*.color1: #ff4242 +*.color9: #ff3242 +! +! Green +*.color2: #74af68 +*.color10: #74cd68 +! +! Yellow +*.color3: #ffad29 +*.color11: #ffb929 +! +! Blue +*.color4: #338f86 +*.color12: #23d7d7 +! +! Magenta +*.color5: #9414e6 +*.color13: #ff37ff +! +! Cyan +*.color6: #23d7d7 +*.color14: #00ede1 +! +! White +*.color7: #e2e2e2 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #67a672 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Paraiso Dark b/assets/colors/schemes/Paraiso Dark new file mode 100644 index 0000000..210ec21 --- /dev/null +++ b/assets/colors/schemes/Paraiso Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a39e9b +*.background: #2f1e2e +*.cursorColor: #a39e9b +! +! Black +*.color0: #2f1e2e +*.color8: #776e71 +! +! Red +*.color1: #ef6155 +*.color9: #ef6155 +! +! Green +*.color2: #48b685 +*.color10: #48b685 +! +! Yellow +*.color3: #fec418 +*.color11: #fec418 +! +! Blue +*.color4: #06b6ef +*.color12: #06b6ef +! +! Magenta +*.color5: #815ba4 +*.color13: #815ba4 +! +! Cyan +*.color6: #5bc4bf +*.color14: #5bc4bf +! +! White +*.color7: #a39e9b +*.color15: #e7e9db +! +! Bold, Italic, Underline +*.colorBD: #a39e9b +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Parasio Dark b/assets/colors/schemes/Parasio Dark new file mode 100644 index 0000000..210ec21 --- /dev/null +++ b/assets/colors/schemes/Parasio Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #a39e9b +*.background: #2f1e2e +*.cursorColor: #a39e9b +! +! Black +*.color0: #2f1e2e +*.color8: #776e71 +! +! Red +*.color1: #ef6155 +*.color9: #ef6155 +! +! Green +*.color2: #48b685 +*.color10: #48b685 +! +! Yellow +*.color3: #fec418 +*.color11: #fec418 +! +! Blue +*.color4: #06b6ef +*.color12: #06b6ef +! +! Magenta +*.color5: #815ba4 +*.color13: #815ba4 +! +! Cyan +*.color6: #5bc4bf +*.color14: #5bc4bf +! +! White +*.color7: #a39e9b +*.color15: #e7e9db +! +! Bold, Italic, Underline +*.colorBD: #a39e9b +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/PaulMillr b/assets/colors/schemes/PaulMillr new file mode 100644 index 0000000..95639b3 --- /dev/null +++ b/assets/colors/schemes/PaulMillr @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f2f2f2 +*.background: #000000 +*.cursorColor: #4d4d4d +! +! Black +*.color0: #2a2a2a +*.color8: #666666 +! +! Red +*.color1: #ff0000 +*.color9: #ff0080 +! +! Green +*.color2: #79ff0f +*.color10: #66ff66 +! +! Yellow +*.color3: #e7bf00 +*.color11: #f3d64e +! +! Blue +*.color4: #396bd7 +*.color12: #709aed +! +! Magenta +*.color5: #b449be +*.color13: #db67e6 +! +! Cyan +*.color6: #66ccff +*.color14: #7adff2 +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/PencilDark b/assets/colors/schemes/PencilDark new file mode 100644 index 0000000..bdf6b2e --- /dev/null +++ b/assets/colors/schemes/PencilDark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f1f1f1 +*.background: #212121 +*.cursorColor: #20bbfc +! +! Black +*.color0: #212121 +*.color8: #424242 +! +! Red +*.color1: #c30771 +*.color9: #fb007a +! +! Green +*.color2: #10a778 +*.color10: #5fd7af +! +! Yellow +*.color3: #a89c14 +*.color11: #f3e430 +! +! Blue +*.color4: #008ec4 +*.color12: #20bbfc +! +! Magenta +*.color5: #523c79 +*.color13: #6855de +! +! Cyan +*.color6: #20a5ba +*.color14: #4fb8cc +! +! White +*.color7: #d9d9d9 +*.color15: #f1f1f1 +! +! Bold, Italic, Underline +*.colorBD: #fb007a +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/PencilLight b/assets/colors/schemes/PencilLight new file mode 100644 index 0000000..055b31b --- /dev/null +++ b/assets/colors/schemes/PencilLight @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #424242 +*.background: #f1f1f1 +*.cursorColor: #20bbfc +! +! Black +*.color0: #212121 +*.color8: #424242 +! +! Red +*.color1: #c30771 +*.color9: #fb007a +! +! Green +*.color2: #10a778 +*.color10: #5fd7af +! +! Yellow +*.color3: #a89c14 +*.color11: #f3e430 +! +! Blue +*.color4: #008ec4 +*.color12: #20bbfc +! +! Magenta +*.color5: #523c79 +*.color13: #6855de +! +! Cyan +*.color6: #20a5ba +*.color14: #4fb8cc +! +! White +*.color7: #d9d9d9 +*.color15: #f1f1f1 +! +! Bold, Italic, Underline +*.colorBD: #fb007a +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Piatto Light b/assets/colors/schemes/Piatto Light new file mode 100644 index 0000000..5a7e5dd --- /dev/null +++ b/assets/colors/schemes/Piatto Light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #414141 +*.background: #ffffff +*.cursorColor: #5e77c8 +! +! Black +*.color0: #414141 +*.color8: #3f3f3f +! +! Red +*.color1: #b23771 +*.color9: #db3365 +! +! Green +*.color2: #66781e +*.color10: #829429 +! +! Yellow +*.color3: #cd6f34 +*.color11: #cd6f34 +! +! Blue +*.color4: #3c5ea8 +*.color12: #3c5ea8 +! +! Magenta +*.color5: #a454b2 +*.color13: #a454b2 +! +! Cyan +*.color6: #66781e +*.color14: #829429 +! +! White +*.color7: #ffffff +*.color15: #f2f2f2 +! +! Bold, Italic, Underline +*.colorBD: #323232 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Pnevma b/assets/colors/schemes/Pnevma new file mode 100644 index 0000000..2a66a9b --- /dev/null +++ b/assets/colors/schemes/Pnevma @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d0d0d0 +*.background: #1c1c1c +*.cursorColor: #e4c9af +! +! Black +*.color0: #2f2e2d +*.color8: #4a4845 +! +! Red +*.color1: #a36666 +*.color9: #d78787 +! +! Green +*.color2: #90a57d +*.color10: #afbea2 +! +! Yellow +*.color3: #d7af87 +*.color11: #e4c9af +! +! Blue +*.color4: #7fa5bd +*.color12: #a1bdce +! +! Magenta +*.color5: #c79ec4 +*.color13: #d7beda +! +! Cyan +*.color6: #8adbb4 +*.color14: #b1e7dd +! +! White +*.color7: #d0d0d0 +*.color15: #efefef +! +! Bold, Italic, Underline +*.colorBD: #e5e5e5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Pro b/assets/colors/schemes/Pro new file mode 100644 index 0000000..18235ea --- /dev/null +++ b/assets/colors/schemes/Pro @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f2f2f2 +*.background: #000000 +*.cursorColor: #4d4d4d +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #990000 +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #00d900 +! +! Yellow +*.color3: #999900 +*.color11: #e5e500 +! +! Blue +*.color4: #2009db +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Red Alert b/assets/colors/schemes/Red Alert new file mode 100644 index 0000000..540a5c9 --- /dev/null +++ b/assets/colors/schemes/Red Alert @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #762423 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #262626 +! +! Red +*.color1: #d62e4e +*.color9: #e02553 +! +! Green +*.color2: #71be6b +*.color10: #aff08c +! +! Yellow +*.color3: #beb86b +*.color11: #dfddb7 +! +! Blue +*.color4: #489bee +*.color12: #65aaf1 +! +! Magenta +*.color5: #e979d7 +*.color13: #ddb7df +! +! Cyan +*.color6: #6bbeb8 +*.color14: #b7dfdd +! +! White +*.color7: #d6d6d6 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ff9c44 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Red Sands b/assets/colors/schemes/Red Sands new file mode 100644 index 0000000..8eac967 --- /dev/null +++ b/assets/colors/schemes/Red Sands @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d7c9a7 +*.background: #7a251e +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #ff3f00 +*.color9: #bb0000 +! +! Green +*.color2: #00bb00 +*.color10: #00bb00 +! +! Yellow +*.color3: #e7b000 +*.color11: #e7b000 +! +! Blue +*.color4: #0072ff +*.color12: #0072ae +! +! Magenta +*.color5: #bb00bb +*.color13: #ff55ff +! +! Cyan +*.color6: #00bbbb +*.color14: #55ffff +! +! White +*.color7: #bbbbbb +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #dfbd22 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Relaxed b/assets/colors/schemes/Relaxed new file mode 100644 index 0000000..08496e7 --- /dev/null +++ b/assets/colors/schemes/Relaxed @@ -0,0 +1,36 @@ +! special +*.foreground: #d8d8d8 +*.background: #343a43 +*.cursorColor: #d8d8d8 + +! black +*.color0: #2c3037 +*.color8: #626262 + +! red +*.color1: #bb5653 +*.color9: #c35956 + +! green +*.color2: #909d62 +*.color10: #9fab76 + +! yellow +*.color3: #eac179 +*.color11: #ecc179 + +! blue +*.color4: #698698 +*.color12: #7da9c7 + +! magenta +*.color5: #b06597 +*.color13: #ba6ca0 + +! cyan +*.color6: #c9dfff +*.color14: #abbacf + +! white +*.color7: #d8d8d8 +*.color15: #f7f7f7 diff --git a/assets/colors/schemes/Rippedcasts b/assets/colors/schemes/Rippedcasts new file mode 100644 index 0000000..d99bb41 --- /dev/null +++ b/assets/colors/schemes/Rippedcasts @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #2b2b2b +*.cursorColor: #7f7f7f +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #cdaf95 +*.color9: #eecbad +! +! Green +*.color2: #a8ff60 +*.color10: #bcee68 +! +! Yellow +*.color3: #bfbb1f +*.color11: #e5e500 +! +! Blue +*.color4: #75a5b0 +*.color12: #86bdc9 +! +! Magenta +*.color5: #ff73fd +*.color13: #e500e5 +! +! Cyan +*.color6: #5a647e +*.color14: #8c9bc4 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #d0f367 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Rose Pine b/assets/colors/schemes/Rose Pine new file mode 100644 index 0000000..1ad1617 --- /dev/null +++ b/assets/colors/schemes/Rose Pine @@ -0,0 +1,44 @@ +! +! Rosé Pine +! https://rosepinetheme.com/ +! +*.foreground: #e0def4 +*.background: #191724 +*.cursorColor: #555169 +! +! Black +*.color0: #26233a +*.color8: #6e6a86 +! +! Red +*.color1: #eb6f92 +*.color9: #eb6f92 +! +! Green +*.color2: #31748f +*.color10: #31748f +! +! Yellow +*.color3: #f6c177 +*.color11: #f6c177 +! +! Blue +*.color4: #9ccfd8 +*.color12: #9ccfd8 + +! Magenta +*.color5: #c4a7e7 +*.color13: #c4a7e7 +! +! Cyan +*.color6: #ebbcba +*.color14: #ebbcba +! +! White +*.color7: #e0def4 +*.color15: #e0def4 +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Rose Pine Dawn b/assets/colors/schemes/Rose Pine Dawn new file mode 100644 index 0000000..54fdb29 --- /dev/null +++ b/assets/colors/schemes/Rose Pine Dawn @@ -0,0 +1,44 @@ +! +! Rosé Pine Dawn +! https://rosepinetheme.com/ +! +*.foreground: #575279 +*.background: #faf4ed +*.cursorColor: #9893a5 +! +! Black +*.color0: #f2e9de +*.color8: #6e6a86 +! +! Red +*.color1: #b4637a +*.color9: #b4637a +! +! Green +*.color2: #286983 +*.color10: #286983 +! +! Yellow +*.color3: #ea9d34 +*.color11: #ea9d34 +! +! Blue +*.color4: #56949f +*.color12: #56949f +! +! Magenta +*.color5: #907aa9 +*.color13: #907aa9 +! +! Cyan +*.color6: #d7827e +*.color14: #d7827e +! +! White +*.color7: #575279 +*.color15: #575279 +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Rose Pine Moon b/assets/colors/schemes/Rose Pine Moon new file mode 100644 index 0000000..2c31986 --- /dev/null +++ b/assets/colors/schemes/Rose Pine Moon @@ -0,0 +1,44 @@ +! +! Rosé Pine Moon +! https://rosepinetheme.com/ +! +*.foreground: #e0def4 +*.background: #232136 +*.cursorColor: #59546d +! +! Black +*.color0: #393552 +*.color8: #817c9c +! +! Red +*.color1: #eb6f92 +*.color9: #eb6f92 +! +! Green +*.color2: #3e8fb0 +*.color10: #3e8fb0 +! +! Yellow +*.color3: #f6c177 +*.color11: #f6c177 +! +! Blue +*.color4: #9ccfd8 +*.color12: #9ccfd8 +! +! Magenta +*.color5: #c4a7e7 +*.color13: #c4a7e7 +! +! Cyan +*.color6: #ea9a97 +*.color14: #ea9a97 +! +! White +*.color7: #e0def4 +*.color15: #e0def4 +! +! Bold, Italic, Underline +!*.colorBD: +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Royal b/assets/colors/schemes/Royal new file mode 100644 index 0000000..1537cc6 --- /dev/null +++ b/assets/colors/schemes/Royal @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #514968 +*.background: #100815 +*.cursorColor: #524966 +! +! Black +*.color0: #241f2b +*.color8: #312d3d +! +! Red +*.color1: #91284c +*.color9: #d5356c +! +! Green +*.color2: #23801c +*.color10: #2cd946 +! +! Yellow +*.color3: #b49d27 +*.color11: #fde83b +! +! Blue +*.color4: #6580b0 +*.color12: #90baf9 +! +! Magenta +*.color5: #674d96 +*.color13: #a479e3 +! +! Cyan +*.color6: #8aaabe +*.color14: #acd4eb +! +! White +*.color7: #524966 +*.color15: #9e8cbd +! +! Bold, Italic, Underline +*.colorBD: #c8bd1d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Ryuuko b/assets/colors/schemes/Ryuuko new file mode 100644 index 0000000..4a7f52d --- /dev/null +++ b/assets/colors/schemes/Ryuuko @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ececec +*.background: #2c3941 +*.cursorColor: #ececec +! +! Black +*.color0: #2c3941 +*.color8: #5d7079 +! +! Red +*.color1: #865f5b +*.color9: #865f5b +! +! Green +*.color2: #66907d +*.color10: #66907d +! +! Yellow +*.color3: #b1a990 +*.color11: #b1a990 +! +! Blue +*.color4: #6a8e95 +*.color12: #6a8e95 +! +! Magenta +*.color5: #b18a73 +*.color13: #b18a73 +! +! Cyan +*.color6: #88b2ac +*.color14: #88b2ac +! +! White +*.color7: #ececec +*.color15: #ececec +! +! Bold, Italic, Underline +*.colorBD: #819090 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/SeaShells b/assets/colors/schemes/SeaShells new file mode 100644 index 0000000..5afcadc --- /dev/null +++ b/assets/colors/schemes/SeaShells @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #deb88d +*.background: #09141b +*.cursorColor: #fca02f +! +! Black +*.color0: #17384c +*.color8: #434b53 +! +! Red +*.color1: #d15123 +*.color9: #d48678 +! +! Green +*.color2: #027c9b +*.color10: #628d98 +! +! Yellow +*.color3: #fca02f +*.color11: #fdd39f +! +! Blue +*.color4: #1e4950 +*.color12: #1bbcdd +! +! Magenta +*.color5: #68d4f1 +*.color13: #bbe3ee +! +! Cyan +*.color6: #50a3b5 +*.color14: #87acb4 +! +! White +*.color7: #deb88d +*.color15: #fee4ce +! +! Bold, Italic, Underline +*.colorBD: #ffe4cc +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Seafoam Pastel b/assets/colors/schemes/Seafoam Pastel new file mode 100644 index 0000000..645e11c --- /dev/null +++ b/assets/colors/schemes/Seafoam Pastel @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d4e7d4 +*.background: #243435 +*.cursorColor: #57647a +! +! Black +*.color0: #757575 +*.color8: #8a8a8a +! +! Red +*.color1: #825d4d +*.color9: #cf937a +! +! Green +*.color2: #728c62 +*.color10: #98d9aa +! +! Yellow +*.color3: #ada16d +*.color11: #fae79d +! +! Blue +*.color4: #4d7b82 +*.color12: #7ac3cf +! +! Magenta +*.color5: #8a7267 +*.color13: #d6b2a1 +! +! Cyan +*.color6: #729494 +*.color14: #ade0e0 +! +! White +*.color7: #e0e0e0 +*.color15: #e0e0e0 +! +! Bold, Italic, Underline +*.colorBD: #648890 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Seti b/assets/colors/schemes/Seti new file mode 100644 index 0000000..6f1dda3 --- /dev/null +++ b/assets/colors/schemes/Seti @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #cacecd +*.background: #111213 +*.cursorColor: #e3bf21 +! +! Black +*.color0: #323232 +*.color8: #323232 +! +! Red +*.color1: #c22832 +*.color9: #c22832 +! +! Green +*.color2: #8ec43d +*.color10: #8ec43d +! +! Yellow +*.color3: #e0c64f +*.color11: #e0c64f +! +! Blue +*.color4: #43a5d5 +*.color12: #43a5d5 +! +! Magenta +*.color5: #8b57b5 +*.color13: #8b57b5 +! +! Cyan +*.color6: #8ec43d +*.color14: #8ec43d +! +! White +*.color7: #eeeeee +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #cacecd +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Shaman b/assets/colors/schemes/Shaman new file mode 100644 index 0000000..bdd5e93 --- /dev/null +++ b/assets/colors/schemes/Shaman @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #405555 +*.background: #001015 +*.cursorColor: #4afcd6 +! +! Black +*.color0: #012026 +*.color8: #384451 +! +! Red +*.color1: #b2302d +*.color9: #ff4242 +! +! Green +*.color2: #00a941 +*.color10: #2aea5e +! +! Yellow +*.color3: #5e8baa +*.color11: #8ed4fd +! +! Blue +*.color4: #449a86 +*.color12: #61d5ba +! +! Magenta +*.color5: #00599d +*.color13: #1298ff +! +! Cyan +*.color6: #5d7e19 +*.color14: #98d028 +! +! White +*.color7: #405555 +*.color15: #58fbd6 +! +! Bold, Italic, Underline +*.colorBD: #53fbd6 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Slate b/assets/colors/schemes/Slate new file mode 100644 index 0000000..38ff9bc --- /dev/null +++ b/assets/colors/schemes/Slate @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #35b1d2 +*.background: #222222 +*.cursorColor: #87d3c4 +! +! Black +*.color0: #222222 +*.color8: #ffffff +! +! Red +*.color1: #e2a8bf +*.color9: #ffcdd9 +! +! Green +*.color2: #81d778 +*.color10: #beffa8 +! +! Yellow +*.color3: #c4c9c0 +*.color11: #d0ccca +! +! Blue +*.color4: #264b49 +*.color12: #7ab0d2 +! +! Magenta +*.color5: #a481d3 +*.color13: #c5a7d9 +! +! Cyan +*.color6: #15ab9c +*.color14: #8cdfe0 +! +! White +*.color7: #02c5e0 +*.color15: #e0e0e0 +! +! Bold, Italic, Underline +*.colorBD: #648890 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Smyck b/assets/colors/schemes/Smyck new file mode 100644 index 0000000..b20626a --- /dev/null +++ b/assets/colors/schemes/Smyck @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f7f7f7 +*.background: #1b1b1b +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #7a7a7a +! +! Red +*.color1: #b84131 +*.color9: #d6837c +! +! Green +*.color2: #7da900 +*.color10: #c4f137 +! +! Yellow +*.color3: #c4a500 +*.color11: #fee14d +! +! Blue +*.color4: #62a3c4 +*.color12: #8dcff0 +! +! Magenta +*.color5: #ba8acc +*.color13: #f79aff +! +! Cyan +*.color6: #207383 +*.color14: #6ad9cf +! +! White +*.color7: #a1a1a1 +*.color15: #f7f7f7 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/SoftServer b/assets/colors/schemes/SoftServer new file mode 100644 index 0000000..6c90fa4 --- /dev/null +++ b/assets/colors/schemes/SoftServer @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #99a3a2 +*.background: #242626 +*.cursorColor: #d2e0de +! +! Black +*.color0: #000000 +*.color8: #666c6c +! +! Red +*.color1: #a2686a +*.color9: #dd5c60 +! +! Green +*.color2: #9aa56a +*.color10: #bfdf55 +! +! Yellow +*.color3: #a3906a +*.color11: #deb360 +! +! Blue +*.color4: #6b8fa3 +*.color12: #62b1df +! +! Magenta +*.color5: #6a71a3 +*.color13: #606edf +! +! Cyan +*.color6: #6ba58f +*.color14: #64e39c +! +! White +*.color7: #99a3a2 +*.color15: #d2e0de +! +! Bold, Italic, Underline +*.colorBD: #d2e0de +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Solarized Darcula b/assets/colors/schemes/Solarized Darcula new file mode 100644 index 0000000..12ce157 --- /dev/null +++ b/assets/colors/schemes/Solarized Darcula @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d2d8d9 +*.background: #3d3f41 +*.cursorColor: #708284 +! +! Black +*.color0: #25292a +*.color8: #25292a +! +! Red +*.color1: #f24840 +*.color9: #f24840 +! +! Green +*.color2: #629655 +*.color10: #629655 +! +! Yellow +*.color3: #b68800 +*.color11: #b68800 +! +! Blue +*.color4: #2075c7 +*.color12: #2075c7 +! +! Magenta +*.color5: #797fd4 +*.color13: #797fd4 +! +! Cyan +*.color6: #15968d +*.color14: #15968d +! +! White +*.color7: #d2d8d9 +*.color15: #d2d8d9 +! +! Bold, Italic, Underline +*.colorBD: #ececec +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Solarized Dark b/assets/colors/schemes/Solarized Dark new file mode 100644 index 0000000..badf86b --- /dev/null +++ b/assets/colors/schemes/Solarized Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #708284 +*.background: #001e27 +*.cursorColor: #708284 +! +! Black +*.color0: #002831 +*.color8: #001e27 +! +! Red +*.color1: #d11c24 +*.color9: #bd3613 +! +! Green +*.color2: #738a05 +*.color10: #475b62 +! +! Yellow +*.color3: #a57706 +*.color11: #536870 +! +! Blue +*.color4: #2176c7 +*.color12: #708284 +! +! Magenta +*.color5: #c61c6f +*.color13: #5956ba +! +! Cyan +*.color6: #259286 +*.color14: #819090 +! +! White +*.color7: #eae3cb +*.color15: #fcf4dc +! +! Bold, Italic, Underline +*.colorBD: #819090 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Solarized Dark - Patched b/assets/colors/schemes/Solarized Dark - Patched new file mode 100644 index 0000000..c63a3b8 --- /dev/null +++ b/assets/colors/schemes/Solarized Dark - Patched @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #708284 +*.background: #001e27 +*.cursorColor: #708284 +! +! Black +*.color0: #002831 +*.color8: #475b62 +! +! Red +*.color1: #d11c24 +*.color9: #bd3613 +! +! Green +*.color2: #738a05 +*.color10: #475b62 +! +! Yellow +*.color3: #a57706 +*.color11: #536870 +! +! Blue +*.color4: #2176c7 +*.color12: #708284 +! +! Magenta +*.color5: #c61c6f +*.color13: #5956ba +! +! Cyan +*.color6: #259286 +*.color14: #819090 +! +! White +*.color7: #eae3cb +*.color15: #fcf4dc +! +! Bold, Italic, Underline +*.colorBD: #819090 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Solarized Dark Higher Contrast b/assets/colors/schemes/Solarized Dark Higher Contrast new file mode 100644 index 0000000..72c00f9 --- /dev/null +++ b/assets/colors/schemes/Solarized Dark Higher Contrast @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #9cc2c3 +*.background: #001e27 +*.cursorColor: #f34b00 +! +! Black +*.color0: #002831 +*.color8: #006488 +! +! Red +*.color1: #d11c24 +*.color9: #f5163b +! +! Green +*.color2: #6cbe6c +*.color10: #51ef84 +! +! Yellow +*.color3: #a57706 +*.color11: #b27e28 +! +! Blue +*.color4: #2176c7 +*.color12: #178ec8 +! +! Magenta +*.color5: #c61c6f +*.color13: #e24d8e +! +! Cyan +*.color6: #259286 +*.color14: #00b39e +! +! White +*.color7: #eae3cb +*.color15: #fcf4dc +! +! Bold, Italic, Underline +*.colorBD: #b5d5d3 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Solarized Light b/assets/colors/schemes/Solarized Light new file mode 100644 index 0000000..4903d72 --- /dev/null +++ b/assets/colors/schemes/Solarized Light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #536870 +*.background: #fcf4dc +*.cursorColor: #536870 +! +! Black +*.color0: #002831 +*.color8: #001e27 +! +! Red +*.color1: #d11c24 +*.color9: #bd3613 +! +! Green +*.color2: #738a05 +*.color10: #475b62 +! +! Yellow +*.color3: #a57706 +*.color11: #536870 +! +! Blue +*.color4: #2176c7 +*.color12: #708284 +! +! Magenta +*.color5: #c61c6f +*.color13: #5956ba +! +! Cyan +*.color6: #259286 +*.color14: #819090 +! +! White +*.color7: #eae3cb +*.color15: #fcf4dc +! +! Bold, Italic, Underline +*.colorBD: #475b62 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/SpaceGray b/assets/colors/schemes/SpaceGray new file mode 100644 index 0000000..081df45 --- /dev/null +++ b/assets/colors/schemes/SpaceGray @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b3b8c3 +*.background: #20242d +*.cursorColor: #b3b8c3 +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #b04b57 +*.color9: #b04b57 +! +! Green +*.color2: #87b379 +*.color10: #87b379 +! +! Yellow +*.color3: #e5c179 +*.color11: #e5c179 +! +! Blue +*.color4: #7d8fa4 +*.color12: #7d8fa4 +! +! Magenta +*.color5: #a47996 +*.color13: #a47996 +! +! Cyan +*.color6: #85a7a5 +*.color14: #85a7a5 +! +! White +*.color7: #b3b8c3 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #b3b8c3 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/SpaceGray Eighties b/assets/colors/schemes/SpaceGray Eighties new file mode 100644 index 0000000..2960aff --- /dev/null +++ b/assets/colors/schemes/SpaceGray Eighties @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #bdbaae +*.background: #222222 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #15171c +*.color8: #555555 +! +! Red +*.color1: #ec5f67 +*.color9: #ff6973 +! +! Green +*.color2: #81a764 +*.color10: #93d493 +! +! Yellow +*.color3: #fec254 +*.color11: #ffd256 +! +! Blue +*.color4: #5486c0 +*.color12: #4d84d1 +! +! Magenta +*.color5: #bf83c1 +*.color13: #ff55ff +! +! Cyan +*.color6: #57c2c1 +*.color14: #83e9e4 +! +! White +*.color7: #efece7 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/SpaceGray Eighties Dull b/assets/colors/schemes/SpaceGray Eighties Dull new file mode 100644 index 0000000..e270adb --- /dev/null +++ b/assets/colors/schemes/SpaceGray Eighties Dull @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c9c6bc +*.background: #222222 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #15171c +*.color8: #555555 +! +! Red +*.color1: #b24a56 +*.color9: #ec5f67 +! +! Green +*.color2: #92b477 +*.color10: #89e986 +! +! Yellow +*.color3: #c6735a +*.color11: #fec254 +! +! Blue +*.color4: #7c8fa5 +*.color12: #5486c0 +! +! Magenta +*.color5: #a5789e +*.color13: #bf83c1 +! +! Cyan +*.color6: #80cdcb +*.color14: #58c2c1 +! +! White +*.color7: #b3b8c3 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Spacedust b/assets/colors/schemes/Spacedust new file mode 100644 index 0000000..7042c6d --- /dev/null +++ b/assets/colors/schemes/Spacedust @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ecf0c1 +*.background: #0a1e24 +*.cursorColor: #708284 +! +! Black +*.color0: #6e5346 +*.color8: #684c31 +! +! Red +*.color1: #e35b00 +*.color9: #ff8a3a +! +! Green +*.color2: #5cab96 +*.color10: #aecab8 +! +! Yellow +*.color3: #e3cd7b +*.color11: #ffc878 +! +! Blue +*.color4: #0f548b +*.color12: #67a0ce +! +! Magenta +*.color5: #e35b00 +*.color13: #ff8a3a +! +! Cyan +*.color6: #06afc7 +*.color14: #83a7b4 +! +! White +*.color7: #f0f1ce +*.color15: #fefff1 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Spiderman b/assets/colors/schemes/Spiderman new file mode 100644 index 0000000..888fb74 --- /dev/null +++ b/assets/colors/schemes/Spiderman @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e3e3e3 +*.background: #1b1d1e +*.cursorColor: #2c3fff +! +! Black +*.color0: #1b1d1e +*.color8: #505354 +! +! Red +*.color1: #e60813 +*.color9: #ff0325 +! +! Green +*.color2: #e22928 +*.color10: #ff3338 +! +! Yellow +*.color3: #e24756 +*.color11: #fe3a35 +! +! Blue +*.color4: #2c3fff +*.color12: #1d50ff +! +! Magenta +*.color5: #2435db +*.color13: #747cff +! +! Cyan +*.color6: #3256ff +*.color14: #6184ff +! +! White +*.color7: #fffef6 +*.color15: #fffff9 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Spring b/assets/colors/schemes/Spring new file mode 100644 index 0000000..7ac7311 --- /dev/null +++ b/assets/colors/schemes/Spring @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #4d4d4c +*.background: #ffffff +*.cursorColor: #4d4d4c +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #ff4d83 +*.color9: #ff0021 +! +! Green +*.color2: #1f8c3b +*.color10: #1fc231 +! +! Yellow +*.color3: #1fc95b +*.color11: #d5b807 +! +! Blue +*.color4: #1dd3ee +*.color12: #15a9fd +! +! Magenta +*.color5: #8959a8 +*.color13: #8959a8 +! +! Cyan +*.color6: #3e999f +*.color14: #3e999f +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #4d4d4c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Square b/assets/colors/schemes/Square new file mode 100644 index 0000000..9b50c15 --- /dev/null +++ b/assets/colors/schemes/Square @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #acacab +*.background: #1a1a1a +*.cursorColor: #fcfbcc +! +! Black +*.color0: #050505 +*.color8: #141414 +! +! Red +*.color1: #e9897c +*.color9: #f99286 +! +! Green +*.color2: #b6377d +*.color10: #c3f786 +! +! Yellow +*.color3: #ecebbe +*.color11: #fcfbcc +! +! Blue +*.color4: #a9cdeb +*.color12: #b6defb +! +! Magenta +*.color5: #75507b +*.color13: #ad7fa8 +! +! Cyan +*.color6: #c9caec +*.color14: #d7d9fc +! +! White +*.color7: #f2f2f2 +*.color15: #e2e2e2 +! +! Bold, Italic, Underline +*.colorBD: #e5e5e5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Sundried b/assets/colors/schemes/Sundried new file mode 100644 index 0000000..4d66bb3 --- /dev/null +++ b/assets/colors/schemes/Sundried @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c9c9c9 +*.background: #1a1818 +*.cursorColor: #ffffff +! +! Black +*.color0: #302b2a +*.color8: #4d4e48 +! +! Red +*.color1: #a7463d +*.color9: #aa000c +! +! Green +*.color2: #587744 +*.color10: #128c21 +! +! Yellow +*.color3: #9d602a +*.color11: #fc6a21 +! +! Blue +*.color4: #485b98 +*.color12: #7999f7 +! +! Magenta +*.color5: #864651 +*.color13: #fd8aa1 +! +! Cyan +*.color6: #9c814f +*.color14: #fad484 +! +! White +*.color7: #c9c9c9 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Symfonic b/assets/colors/schemes/Symfonic new file mode 100644 index 0000000..a185452 --- /dev/null +++ b/assets/colors/schemes/Symfonic @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #000000 +*.cursorColor: #dc322f +! +! Black +*.color0: #000000 +*.color8: #1b1d21 +! +! Red +*.color1: #dc322f +*.color9: #dc322f +! +! Green +*.color2: #56db3a +*.color10: #56db3a +! +! Yellow +*.color3: #ff8400 +*.color11: #ff8400 +! +! Blue +*.color4: #0084d4 +*.color12: #0084d4 +! +! Magenta +*.color5: #b729d9 +*.color13: #b729d9 +! +! Cyan +*.color6: #ccccff +*.color14: #ccccff +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ff8400 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tango b/assets/colors/schemes/Tango new file mode 100644 index 0000000..a56d813 --- /dev/null +++ b/assets/colors/schemes/Tango @@ -0,0 +1,36 @@ +! special +*.foreground: #babdb6 +*.background: #000000 +*.cursorColor: #babdb6 + +! black +*.color0: #2e3436 +*.color8: #555753 + +! red +*.color1: #cc0000 +*.color9: #ef2929 + +! green +*.color2: #4e9a06 +*.color10: #8ae234 + +! yellow +*.color3: #c4a000 +*.color11: #fce94f + +! blue +*.color4: #3465a4 +*.color12: #729fcf + +! magenta +*.color5: #75507b +*.color13: #ad7fa8 + +! cyan +*.color6: #06989a +*.color14: #34e2e2 + +! white +*.color7: #d3d7cf +*.color15: #eeeeec diff --git a/assets/colors/schemes/Teerb b/assets/colors/schemes/Teerb new file mode 100644 index 0000000..5b25906 --- /dev/null +++ b/assets/colors/schemes/Teerb @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #d0d0d0 +*.background: #262626 +*.cursorColor: #e4c9af +! +! Black +*.color0: #1c1c1c +*.color8: #1c1c1c +! +! Red +*.color1: #d68686 +*.color9: #d68686 +! +! Green +*.color2: #aed686 +*.color10: #aed686 +! +! Yellow +*.color3: #d7af87 +*.color11: #e4c9af +! +! Blue +*.color4: #86aed6 +*.color12: #86aed6 +! +! Magenta +*.color5: #d6aed6 +*.color13: #d6aed6 +! +! Cyan +*.color6: #8adbb4 +*.color14: #b1e7dd +! +! White +*.color7: #d0d0d0 +*.color15: #efefef +! +! Bold, Italic, Underline +*.colorBD: #e5e5e5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Terminal Basic b/assets/colors/schemes/Terminal Basic new file mode 100644 index 0000000..b96b93a --- /dev/null +++ b/assets/colors/schemes/Terminal Basic @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #000000 +*.background: #ffffff +*.cursorColor: #7f7f7f +! +! Black +*.color0: #000000 +*.color8: #666666 +! +! Red +*.color1: #990000 +*.color9: #e50000 +! +! Green +*.color2: #00a600 +*.color10: #00d900 +! +! Yellow +*.color3: #999900 +*.color11: #e5e500 +! +! Blue +*.color4: #0000b2 +*.color12: #0000ff +! +! Magenta +*.color5: #b200b2 +*.color13: #e500e5 +! +! Cyan +*.color6: #00a6b2 +*.color14: #00e5e5 +! +! White +*.color7: #bfbfbf +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #000000 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Thayer Bright b/assets/colors/schemes/Thayer Bright new file mode 100644 index 0000000..6a2d359 --- /dev/null +++ b/assets/colors/schemes/Thayer Bright @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #f8f8f8 +*.background: #1b1d1e +*.cursorColor: #fc971f +! +! Black +*.color0: #1b1d1e +*.color8: #505354 +! +! Red +*.color1: #f92672 +*.color9: #ff5995 +! +! Green +*.color2: #4df840 +*.color10: #b6e354 +! +! Yellow +*.color3: #f4fd22 +*.color11: #feed6c +! +! Blue +*.color4: #2757d6 +*.color12: #3f78ff +! +! Magenta +*.color5: #8c54fe +*.color13: #9e6ffe +! +! Cyan +*.color6: #38c8b5 +*.color14: #23cfd5 +! +! White +*.color7: #ccccc6 +*.color15: #f8f8f2 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/The Hulk b/assets/colors/schemes/The Hulk new file mode 100644 index 0000000..e0d9e93 --- /dev/null +++ b/assets/colors/schemes/The Hulk @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b5b5b5 +*.background: #1b1d1e +*.cursorColor: #16b61b +! +! Black +*.color0: #1b1d1e +*.color8: #505354 +! +! Red +*.color1: #269d1b +*.color9: #8dff2a +! +! Green +*.color2: #13ce30 +*.color10: #48ff77 +! +! Yellow +*.color3: #63e457 +*.color11: #3afe16 +! +! Blue +*.color4: #2525f5 +*.color12: #506b95 +! +! Magenta +*.color5: #641f74 +*.color13: #72589d +! +! Cyan +*.color6: #378ca9 +*.color14: #4085a6 +! +! White +*.color7: #d9d8d1 +*.color15: #e5e6e1 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tomorrow b/assets/colors/schemes/Tomorrow new file mode 100644 index 0000000..40674f9 --- /dev/null +++ b/assets/colors/schemes/Tomorrow @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #4d4d4c +*.background: #ffffff +*.cursorColor: #4d4d4c +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #c82829 +*.color9: #c82829 +! +! Green +*.color2: #718c00 +*.color10: #718c00 +! +! Yellow +*.color3: #eab700 +*.color11: #eab700 +! +! Blue +*.color4: #4271ae +*.color12: #4271ae +! +! Magenta +*.color5: #8959a8 +*.color13: #8959a8 +! +! Cyan +*.color6: #3e999f +*.color14: #3e999f +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #4d4d4c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tomorrow Night b/assets/colors/schemes/Tomorrow Night new file mode 100644 index 0000000..02bca58 --- /dev/null +++ b/assets/colors/schemes/Tomorrow Night @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #c5c8c6 +*.background: #1d1f21 +*.cursorColor: #c5c8c6 +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #cc6666 +*.color9: #cc6666 +! +! Green +*.color2: #b5bd68 +*.color10: #b5bd68 +! +! Yellow +*.color3: #f0c674 +*.color11: #f0c674 +! +! Blue +*.color4: #81a2be +*.color12: #81a2be +! +! Magenta +*.color5: #b294bb +*.color13: #b294bb +! +! Cyan +*.color6: #8abeb7 +*.color14: #8abeb7 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #c5c8c6 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tomorrow Night Blue b/assets/colors/schemes/Tomorrow Night Blue new file mode 100644 index 0000000..aac3cbe --- /dev/null +++ b/assets/colors/schemes/Tomorrow Night Blue @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #002451 +*.cursorColor: #ffffff +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #ff9da4 +*.color9: #ff9da4 +! +! Green +*.color2: #d1f1a9 +*.color10: #d1f1a9 +! +! Yellow +*.color3: #ffeead +*.color11: #ffeead +! +! Blue +*.color4: #bbdaff +*.color12: #bbdaff +! +! Magenta +*.color5: #ebbbff +*.color13: #ebbbff +! +! Cyan +*.color6: #99ffff +*.color14: #99ffff +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tomorrow Night Bright b/assets/colors/schemes/Tomorrow Night Bright new file mode 100644 index 0000000..50bf55a --- /dev/null +++ b/assets/colors/schemes/Tomorrow Night Bright @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #eaeaea +*.background: #000000 +*.cursorColor: #eaeaea +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #d54e53 +*.color9: #d54e53 +! +! Green +*.color2: #b9ca4a +*.color10: #b9ca4a +! +! Yellow +*.color3: #e7c547 +*.color11: #e7c547 +! +! Blue +*.color4: #7aa6da +*.color12: #7aa6da +! +! Magenta +*.color5: #c397d8 +*.color13: #c397d8 +! +! Cyan +*.color6: #70c0b1 +*.color14: #70c0b1 +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #eaeaea +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Tomorrow Night Eighties b/assets/colors/schemes/Tomorrow Night Eighties new file mode 100644 index 0000000..f71bc79 --- /dev/null +++ b/assets/colors/schemes/Tomorrow Night Eighties @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #cccccc +*.background: #2d2d2d +*.cursorColor: #cccccc +! +! Black +*.color0: #000000 +*.color8: #000000 +! +! Red +*.color1: #f2777a +*.color9: #f2777a +! +! Green +*.color2: #99cc99 +*.color10: #99cc99 +! +! Yellow +*.color3: #ffcc66 +*.color11: #ffcc66 +! +! Blue +*.color4: #6699cc +*.color12: #6699cc +! +! Magenta +*.color5: #cc99cc +*.color13: #cc99cc +! +! Cyan +*.color6: #66cccc +*.color14: #66cccc +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #cccccc +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/ToyChest b/assets/colors/schemes/ToyChest new file mode 100644 index 0000000..ab94027 --- /dev/null +++ b/assets/colors/schemes/ToyChest @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #31d07b +*.background: #24364b +*.cursorColor: #d5d5d5 +! +! Black +*.color0: #2c3f58 +*.color8: #336889 +! +! Red +*.color1: #be2d26 +*.color9: #dd5944 +! +! Green +*.color2: #1a9172 +*.color10: #31d07b +! +! Yellow +*.color3: #db8e27 +*.color11: #e7d84b +! +! Blue +*.color4: #325d96 +*.color12: #34a6da +! +! Magenta +*.color5: #8a5edc +*.color13: #ae6bdc +! +! Cyan +*.color6: #35a08f +*.color14: #42c3ae +! +! White +*.color7: #23d183 +*.color15: #d5d5d5 +! +! Bold, Italic, Underline +*.colorBD: #2bff9f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Treehouse b/assets/colors/schemes/Treehouse new file mode 100644 index 0000000..e3a0842 --- /dev/null +++ b/assets/colors/schemes/Treehouse @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #786b53 +*.background: #191919 +*.cursorColor: #fac814 +! +! Black +*.color0: #321300 +*.color8: #433626 +! +! Red +*.color1: #b2270e +*.color9: #ed5d20 +! +! Green +*.color2: #44a900 +*.color10: #55f238 +! +! Yellow +*.color3: #aa820c +*.color11: #f2b732 +! +! Blue +*.color4: #58859a +*.color12: #85cfed +! +! Magenta +*.color5: #97363d +*.color13: #e14c5a +! +! Cyan +*.color6: #b25a1e +*.color14: #f07d14 +! +! White +*.color7: #786b53 +*.color15: #ffc800 +! +! Bold, Italic, Underline +*.colorBD: #fac800 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Twilight b/assets/colors/schemes/Twilight new file mode 100644 index 0000000..01ad5d9 --- /dev/null +++ b/assets/colors/schemes/Twilight @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffd4 +*.background: #141414 +*.cursorColor: #ffffff +! +! Black +*.color0: #141414 +*.color8: #262626 +! +! Red +*.color1: #c06d44 +*.color9: #de7c4c +! +! Green +*.color2: #afb97a +*.color10: #ccd88c +! +! Yellow +*.color3: #c2a86c +*.color11: #e2c47e +! +! Blue +*.color4: #44474a +*.color12: #5a5e62 +! +! Magenta +*.color5: #b4be7c +*.color13: #d0dc8e +! +! Cyan +*.color6: #778385 +*.color14: #8a989b +! +! White +*.color7: #ffffd4 +*.color15: #ffffd4 +! +! Bold, Italic, Underline +*.colorBD: #ffffd4 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Ubuntu b/assets/colors/schemes/Ubuntu new file mode 100644 index 0000000..512e34b --- /dev/null +++ b/assets/colors/schemes/Ubuntu @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #eeeeec +*.background: #300a24 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #2e3436 +*.color8: #555753 +! +! Red +*.color1: #cc0000 +*.color9: #ef2929 +! +! Green +*.color2: #4e9a06 +*.color10: #8ae234 +! +! Yellow +*.color3: #c4a000 +*.color11: #fce94f +! +! Blue +*.color4: #3465a4 +*.color12: #729fcf +! +! Magenta +*.color5: #75507b +*.color13: #ad7fa8 +! +! Cyan +*.color6: #06989a +*.color14: #34e2e2 +! +! White +*.color7: #d3d7cf +*.color15: #eeeeec +! +! Bold, Italic, Underline +*.colorBD: #eeeeec +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/UnderTheSea b/assets/colors/schemes/UnderTheSea new file mode 100644 index 0000000..6690fe1 --- /dev/null +++ b/assets/colors/schemes/UnderTheSea @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #011116 +*.cursorColor: #4afcd6 +! +! Black +*.color0: #022026 +*.color8: #384451 +! +! Red +*.color1: #b2302d +*.color9: #ff4242 +! +! Green +*.color2: #00a941 +*.color10: #2aea5e +! +! Yellow +*.color3: #59819c +*.color11: #8ed4fd +! +! Blue +*.color4: #459a86 +*.color12: #61d5ba +! +! Magenta +*.color5: #00599d +*.color13: #1298ff +! +! Cyan +*.color6: #5d7e19 +*.color14: #98d028 +! +! White +*.color7: #405555 +*.color15: #58fbd6 +! +! Bold, Italic, Underline +*.colorBD: #2bffd2 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Urple b/assets/colors/schemes/Urple new file mode 100644 index 0000000..e55881f --- /dev/null +++ b/assets/colors/schemes/Urple @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #877a9b +*.background: #1b1b23 +*.cursorColor: #a063eb +! +! Black +*.color0: #000000 +*.color8: #5d3225 +! +! Red +*.color1: #b0425b +*.color9: #ff6388 +! +! Green +*.color2: #37a415 +*.color10: #29e620 +! +! Yellow +*.color3: #ad5c42 +*.color11: #f08161 +! +! Blue +*.color4: #564d9b +*.color12: #867aed +! +! Magenta +*.color5: #6c3ca1 +*.color13: #a05eee +! +! Cyan +*.color6: #808080 +*.color14: #eaeaea +! +! White +*.color7: #87799c +*.color15: #bfa3ff +! +! Bold, Italic, Underline +*.colorBD: #a063eb +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Vaughn b/assets/colors/schemes/Vaughn new file mode 100644 index 0000000..244b96e --- /dev/null +++ b/assets/colors/schemes/Vaughn @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dcdccc +*.background: #25234f +*.cursorColor: #ff5555 +! +! Black +*.color0: #25234f +*.color8: #709080 +! +! Red +*.color1: #705050 +*.color9: #dca3a3 +! +! Green +*.color2: #60b48a +*.color10: #60b48a +! +! Yellow +*.color3: #dfaf8f +*.color11: #f0dfaf +! +! Blue +*.color4: #5555ff +*.color12: #5555ff +! +! Magenta +*.color5: #f08cc3 +*.color13: #ec93d3 +! +! Cyan +*.color6: #8cd0d3 +*.color14: #93e0e3 +! +! White +*.color7: #709080 +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ff5e7d +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/VibrantInk b/assets/colors/schemes/VibrantInk new file mode 100644 index 0000000..41105ca --- /dev/null +++ b/assets/colors/schemes/VibrantInk @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #000000 +*.cursorColor: #ffffff +! +! Black +*.color0: #878787 +*.color8: #555555 +! +! Red +*.color1: #ff6600 +*.color9: #ff0000 +! +! Green +*.color2: #ccff04 +*.color10: #00ff00 +! +! Yellow +*.color3: #ffcc00 +*.color11: #ffff00 +! +! Blue +*.color4: #44b4cc +*.color12: #0000ff +! +! Magenta +*.color5: #9933cc +*.color13: #ff00ff +! +! Cyan +*.color6: #44b4cc +*.color14: #00ffff +! +! White +*.color7: #f5f5f5 +*.color15: #e5e5e5 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Violet Dark b/assets/colors/schemes/Violet Dark new file mode 100644 index 0000000..06fd9d3 --- /dev/null +++ b/assets/colors/schemes/Violet Dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #708284 +*.background: #1c1d1f +*.cursorColor: #708284 +! +! Black +*.color0: #56595c +*.color8: #45484b +! +! Red +*.color1: #c94c22 +*.color9: #bd3613 +! +! Green +*.color2: #85981c +*.color10: #738a04 +! +! Yellow +*.color3: #b4881d +*.color11: #a57705 +! +! Blue +*.color4: #2e8bce +*.color12: #2176c7 +! +! Magenta +*.color5: #d13a82 +*.color13: #c61c6f +! +! Cyan +*.color6: #32a198 +*.color14: #259286 +! +! White +*.color7: #c9c6bd +*.color15: #c9c6bd +! +! Bold, Italic, Underline +*.colorBD: #475b62 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Violet Light b/assets/colors/schemes/Violet Light new file mode 100644 index 0000000..e233bd0 --- /dev/null +++ b/assets/colors/schemes/Violet Light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #536870 +*.background: #fcf4dc +*.cursorColor: #536870 +! +! Black +*.color0: #56595c +*.color8: #45484b +! +! Red +*.color1: #c94c22 +*.color9: #bd3613 +! +! Green +*.color2: #85981c +*.color10: #738a04 +! +! Yellow +*.color3: #b4881d +*.color11: #a57705 +! +! Blue +*.color4: #2e8bce +*.color12: #2176c7 +! +! Magenta +*.color5: #d13a82 +*.color13: #c61c6f +! +! Cyan +*.color6: #32a198 +*.color14: #259286 +! +! White +*.color7: #d3d0c9 +*.color15: #c9c6bd +! +! Bold, Italic, Underline +*.colorBD: #475b62 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/WarmNeon b/assets/colors/schemes/WarmNeon new file mode 100644 index 0000000..42acbff --- /dev/null +++ b/assets/colors/schemes/WarmNeon @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #afdab6 +*.background: #404040 +*.cursorColor: #30ff24 +! +! Black +*.color0: #000000 +*.color8: #fefcfc +! +! Red +*.color1: #e24346 +*.color9: #e97071 +! +! Green +*.color2: #39b13a +*.color10: #9cc090 +! +! Yellow +*.color3: #dae145 +*.color11: #ddda7a +! +! Blue +*.color4: #4261c5 +*.color12: #7b91d6 +! +! Magenta +*.color5: #f920fb +*.color13: #f674ba +! +! Cyan +*.color6: #2abbd4 +*.color14: #5ed1e5 +! +! White +*.color7: #d0b8a3 +*.color15: #d8c8bb +! +! Bold, Italic, Underline +*.colorBD: #22ff0c +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Wez b/assets/colors/schemes/Wez new file mode 100644 index 0000000..f10161c --- /dev/null +++ b/assets/colors/schemes/Wez @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #b3b3b3 +*.background: #000000 +*.cursorColor: #53ae71 +! +! Black +*.color0: #000000 +*.color8: #555555 +! +! Red +*.color1: #cc5555 +*.color9: #ff5555 +! +! Green +*.color2: #55cc55 +*.color10: #55ff55 +! +! Yellow +*.color3: #cdcd55 +*.color11: #ffff55 +! +! Blue +*.color4: #5555cc +*.color12: #5555ff +! +! Magenta +*.color5: #cc55cc +*.color13: #ff55ff +! +! Cyan +*.color6: #7acaca +*.color14: #55ffff +! +! White +*.color7: #cccccc +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ff6347 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/WildCherry b/assets/colors/schemes/WildCherry new file mode 100644 index 0000000..15cfbc2 --- /dev/null +++ b/assets/colors/schemes/WildCherry @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dafaff +*.background: #1f1726 +*.cursorColor: #dd00ff +! +! Black +*.color0: #000507 +*.color8: #009cc9 +! +! Red +*.color1: #d94085 +*.color9: #da6bac +! +! Green +*.color2: #2ab250 +*.color10: #f4dca5 +! +! Yellow +*.color3: #ffd16f +*.color11: #eac066 +! +! Blue +*.color4: #883cdc +*.color12: #308cba +! +! Magenta +*.color5: #ececec +*.color13: #ae636b +! +! Cyan +*.color6: #c1b8b7 +*.color14: #ff919d +! +! White +*.color7: #fff8de +*.color15: #e4838d +! +! Bold, Italic, Underline +*.colorBD: #819090 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Wombat b/assets/colors/schemes/Wombat new file mode 100644 index 0000000..6e0d147 --- /dev/null +++ b/assets/colors/schemes/Wombat @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dedacf +*.background: #171717 +*.cursorColor: #bbbbbb +! +! Black +*.color0: #000000 +*.color8: #313131 +! +! Red +*.color1: #ff615a +*.color9: #f58c80 +! +! Green +*.color2: #b1e969 +*.color10: #ddf88f +! +! Yellow +*.color3: #ebd99c +*.color11: #eee5b2 +! +! Blue +*.color4: #5da9f6 +*.color12: #a5c7ff +! +! Magenta +*.color5: #e86aff +*.color13: #ddaaff +! +! Cyan +*.color6: #82fff7 +*.color14: #b7fff9 +! +! White +*.color7: #dedacf +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Wryan b/assets/colors/schemes/Wryan new file mode 100644 index 0000000..70e103a --- /dev/null +++ b/assets/colors/schemes/Wryan @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #999993 +*.background: #101010 +*.cursorColor: #9e9ecb +! +! Black +*.color0: #333333 +*.color8: #3d3d3d +! +! Red +*.color1: #8c4665 +*.color9: #bf4d80 +! +! Green +*.color2: #287373 +*.color10: #53a6a6 +! +! Yellow +*.color3: #7c7c99 +*.color11: #9e9ecb +! +! Blue +*.color4: #395573 +*.color12: #477ab3 +! +! Magenta +*.color5: #5e468c +*.color13: #7e62b3 +! +! Cyan +*.color6: #31658c +*.color14: #6096bf +! +! White +*.color7: #899ca1 +*.color15: #c0c0c0 +! +! Bold, Italic, Underline +*.colorBD: #ffffff +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/Zenburn b/assets/colors/schemes/Zenburn new file mode 100644 index 0000000..bc78998 --- /dev/null +++ b/assets/colors/schemes/Zenburn @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #dcdccc +*.background: #3f3f3f +*.cursorColor: #73635a +! +! Black +*.color0: #4d4d4d +*.color8: #709080 +! +! Red +*.color1: #705050 +*.color9: #dca3a3 +! +! Green +*.color2: #60b48a +*.color10: #c3bf9f +! +! Yellow +*.color3: #f0dfaf +*.color11: #e0cf9f +! +! Blue +*.color4: #506070 +*.color12: #94bff3 +! +! Magenta +*.color5: #dc8cc3 +*.color13: #ec93d3 +! +! Cyan +*.color6: #8cd0d3 +*.color14: #93e0e3 +! +! White +*.color7: #dcdccc +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #dcdccc +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/ayu b/assets/colors/schemes/ayu new file mode 100644 index 0000000..8e72bc6 --- /dev/null +++ b/assets/colors/schemes/ayu @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #e6e1cf +*.background: #0f1419 +*.cursorColor: #f29718 +! +! Black +*.color0: #000000 +*.color8: #323232 +! +! Red +*.color1: #ff3333 +*.color9: #ff6565 +! +! Green +*.color2: #b8cc52 +*.color10: #eafe84 +! +! Yellow +*.color3: #e7c547 +*.color11: #fff779 +! +! Blue +*.color4: #36a3d9 +*.color12: #68d5ff +! +! Magenta +*.color5: #f07178 +*.color13: #ffa3aa +! +! Cyan +*.color6: #95e6cb +*.color14: #c7fffd +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #e6e1cf +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/ayu_light b/assets/colors/schemes/ayu_light new file mode 100644 index 0000000..be7213e --- /dev/null +++ b/assets/colors/schemes/ayu_light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #5c6773 +*.background: #fafafa +*.cursorColor: #ff6a00 +! +! Black +*.color0: #000000 +*.color8: #323232 +! +! Red +*.color1: #ff3333 +*.color9: #ff6565 +! +! Green +*.color2: #86b300 +*.color10: #b8e532 +! +! Yellow +*.color3: #f29718 +*.color11: #ffc94a +! +! Blue +*.color4: #41a6d9 +*.color12: #73d8ff +! +! Magenta +*.color5: #f07178 +*.color13: #ffa3aa +! +! Cyan +*.color6: #4dbf99 +*.color14: #7ff1cb +! +! White +*.color7: #ffffff +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #5c6773 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-cave-dark b/assets/colors/schemes/base2tone-cave-dark new file mode 100644 index 0000000..ab3a06e --- /dev/null +++ b/assets/colors/schemes/base2tone-cave-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #9f999b +*.background: #222021 +*.cursorColor: #996e00 +! +! Black +*.color0: #222021 +*.color8: #635f60 +! +! Red +*.color1: #936c7a +*.color9: #ddaf3c +! +! Green +*.color2: #cca133 +*.color10: #2f2d2e +! +! Yellow +*.color3: #ffcc4d +*.color11: #565254 +! +! Blue +*.color4: #9c818b +*.color12: #706b6d +! +! Magenta +*.color5: #cca133 +*.color13: #f0a8c1 +! +! Cyan +*.color6: #d27998 +*.color14: #c39622 +! +! White +*.color7: #9f999b +*.color15: #ffebf2 +! +! Bold, Italic, Underline +*.colorBD: #9f999b +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-desert-dark b/assets/colors/schemes/base2tone-desert-dark new file mode 100644 index 0000000..8b750e6 --- /dev/null +++ b/assets/colors/schemes/base2tone-desert-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #ada594 +*.background: #292724 +*.cursorColor: #bc672f +! +! Black +*.color0: #292724 +*.color8: #7e7767 +! +! Red +*.color1: #816f4b +*.color9: #f29d63 +! +! Green +*.color2: #ec9255 +*.color10: #3d3a34 +! +! Yellow +*.color3: #ffb380 +*.color11: #615c51 +! +! Blue +*.color4: #957e50 +*.color12: #908774 +! +! Magenta +*.color5: #ec9255 +*.color13: #ddcba6 +! +! Cyan +*.color6: #ac8e53 +*.color14: #e58748 +! +! White +*.color7: #ada594 +*.color15: #f2ead9 +! +! Bold, Italic, Underline +*.colorBD: #ada594 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-drawbridge-dark b/assets/colors/schemes/base2tone-drawbridge-dark new file mode 100644 index 0000000..c197ead --- /dev/null +++ b/assets/colors/schemes/base2tone-drawbridge-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #9094a7 +*.background: #1b1f32 +*.cursorColor: #289dbd +! +! Black +*.color0: #1b1f32 +*.color8: #51587b +! +! Red +*.color1: #627af4 +*.color9: #75d5f0 +! +! Green +*.color2: #67c9e4 +*.color10: #252a41 +! +! Yellow +*.color3: #99e9ff +*.color11: #444b6f +! +! Blue +*.color4: #7289fd +*.color12: #5e6587 +! +! Magenta +*.color5: #67c9e4 +*.color13: #c3cdfe +! +! Cyan +*.color6: #8b9efd +*.color14: #5cbcd6 +! +! White +*.color7: #9094a7 +*.color15: #e1e6ff +! +! Bold, Italic, Underline +*.colorBD: #9094a7 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-evening-dark b/assets/colors/schemes/base2tone-evening-dark new file mode 100644 index 0000000..63300f2 --- /dev/null +++ b/assets/colors/schemes/base2tone-evening-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #a4a1b5 +*.background: #2a2734 +*.cursorColor: #b37537 +! +! Black +*.color0: #2a2734 +*.color8: #6c6783 +! +! Red +*.color1: #8a75f5 +*.color9: #ffb870 +! +! Green +*.color2: #ffad5c +*.color10: #363342 +! +! Yellow +*.color3: #ffcc99 +*.color11: #545167 +! +! Blue +*.color4: #9a86fd +*.color12: #787391 +! +! Magenta +*.color5: #ffad5c +*.color13: #d9d2fe +! +! Cyan +*.color6: #afa0fe +*.color14: #ffa142 +! +! White +*.color7: #a4a1b5 +*.color15: #eeebff +! +! Bold, Italic, Underline +*.colorBD: #a4a1b5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-forest-dark b/assets/colors/schemes/base2tone-forest-dark new file mode 100644 index 0000000..8aa45de --- /dev/null +++ b/assets/colors/schemes/base2tone-forest-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #a1b5a1 +*.background: #2a2d2a +*.cursorColor: #656b47 +! +! Black +*.color0: #2a2d2a +*.color8: #535f53 +! +! Red +*.color1: #5c705c +*.color9: #cbe25a +! +! Green +*.color2: #bfd454 +*.color10: #353b35 +! +! Yellow +*.color3: #e5fb79 +*.color11: #485148 +! +! Blue +*.color4: #687d68 +*.color12: #5e6e5e +! +! Magenta +*.color5: #bfd454 +*.color13: #c8e4c8 +! +! Cyan +*.color6: #8fae8f +*.color14: #b1c44f +! +! White +*.color7: #a1b5a1 +*.color15: #f0fff0 +! +! Bold, Italic, Underline +*.colorBD: #a1b5a1 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-heath-dark b/assets/colors/schemes/base2tone-heath-dark new file mode 100644 index 0000000..79dcc54 --- /dev/null +++ b/assets/colors/schemes/base2tone-heath-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #9e999f +*.background: #222022 +*.cursorColor: #995900 +! +! Black +*.color0: #222022 +*.color8: #635f63 +! +! Red +*.color1: #8f6c93 +*.color9: #d9b98c +! +! Green +*.color2: #cc8c33 +*.color10: #2f2d2f +! +! Yellow +*.color3: #ffd599 +*.color11: #575158 +! +! Blue +*.color4: #9a819c +*.color12: #6f6b70 +! +! Magenta +*.color5: #cc8c33 +*.color13: #eaa8f0 +! +! Cyan +*.color6: #cb79d2 +*.color14: #c38022 +! +! White +*.color7: #9e999f +*.color15: #fdebff +! +! Bold, Italic, Underline +*.colorBD: #9e999f +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-heath-light b/assets/colors/schemes/base2tone-heath-light new file mode 100644 index 0000000..3690e09 --- /dev/null +++ b/assets/colors/schemes/base2tone-heath-light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #575158 +*.background: #fbfaf9 +*.cursorColor: #eaa8f0 +! +! Black +*.color0: #222022 +*.color8: #635f63 +! +! Red +*.color1: #8f6c93 +*.color9: #d9b98c +! +! Green +*.color2: #cc8c33 +*.color10: #2f2d2f +! +! Yellow +*.color3: #ffd599 +*.color11: #575158 +! +! Blue +*.color4: #9a819c +*.color12: #6f6b70 +! +! Magenta +*.color5: #b87414 +*.color13: #eaa8f0 +! +! Cyan +*.color6: #cb79d2 +*.color14: #c38022 +! +! White +*.color7: #9e999f +*.color15: #fbfaf9 +! +! Bold, Italic, Underline +*.colorBD: #575158 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-lake-dark b/assets/colors/schemes/base2tone-lake-dark new file mode 100644 index 0000000..b5f8384 --- /dev/null +++ b/assets/colors/schemes/base2tone-lake-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #7ba8b7 +*.background: #192d34 +*.cursorColor: #84740b +! +! Black +*.color0: #192d34 +*.color8: #3d6876 +! +! Red +*.color1: #3e91ac +*.color9: #d6c65c +! +! Green +*.color2: #cbbb4d +*.color10: #223c44 +! +! Yellow +*.color3: #ffeb66 +*.color11: #335966 +! +! Blue +*.color4: #499fbc +*.color12: #467686 +! +! Magenta +*.color5: #cbbb4d +*.color13: #a5d8e9 +! +! Cyan +*.color6: #62b1cb +*.color14: #c4b031 +! +! White +*.color7: #7ba8b7 +*.color15: #e1f7ff +! +! Bold, Italic, Underline +*.colorBD: #7ba8b7 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-meadow-dark b/assets/colors/schemes/base2tone-meadow-dark new file mode 100644 index 0000000..27b9768 --- /dev/null +++ b/assets/colors/schemes/base2tone-meadow-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #7b9eb7 +*.background: #192834 +*.cursorColor: #4d8217 +! +! Black +*.color0: #192834 +*.color8: #3d5e76 +! +! Red +*.color1: #277fbe +*.color9: #8cdd3c +! +! Green +*.color2: #80bf40 +*.color10: #223644 +! +! Yellow +*.color3: #a6f655 +*.color11: #335166 +! +! Blue +*.color4: #4299d7 +*.color12: #466b86 +! +! Magenta +*.color5: #80bf40 +*.color13: #afddfe +! +! Cyan +*.color6: #47adf5 +*.color14: #73b234 +! +! White +*.color7: #7b9eb7 +*.color15: #d1ecff +! +! Bold, Italic, Underline +*.colorBD: #7b9eb7 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-morning-light b/assets/colors/schemes/base2tone-morning-light new file mode 100644 index 0000000..862728f --- /dev/null +++ b/assets/colors/schemes/base2tone-morning-light @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #4f5664 +*.background: #faf8f5 +*.cursorColor: #b7c9eb +! +! Black +*.color0: #232834 +*.color8: #656e81 +! +! Red +*.color1: #1659df +*.color9: #c6b28b +! +! Green +*.color2: #b29762 +*.color10: #31363f +! +! Yellow +*.color3: #e5ddcd +*.color11: #4f5664 +! +! Blue +*.color4: #3d75e6 +*.color12: #707a8f +! +! Magenta +*.color5: #896724 +*.color13: #b7c9eb +! +! Cyan +*.color6: #728fcb +*.color14: #9a7c42 +! +! White +*.color7: #8d95a5 +*.color15: #faf8f5 +! +! Bold, Italic, Underline +*.colorBD: #4f5664 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-pool-dark b/assets/colors/schemes/base2tone-pool-dark new file mode 100644 index 0000000..54fbc4d --- /dev/null +++ b/assets/colors/schemes/base2tone-pool-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #9a90a7 +*.background: #2a2433 +*.cursorColor: #cf504a +! +! Black +*.color0: #2a2433 +*.color8: #635775 +! +! Red +*.color1: #aa75f5 +*.color9: #fc8983 +! +! Green +*.color2: #f87972 +*.color10: #372f42 +! +! Yellow +*.color3: #ffb6b3 +*.color11: #574b68 +! +! Blue +*.color4: #b886fd +*.color12: #706383 +! +! Magenta +*.color5: #f87972 +*.color13: #e4d2fe +! +! Cyan +*.color6: #c7a0fe +*.color14: #f36f68 +! +! White +*.color7: #9a90a7 +*.color15: #f3ebff +! +! Bold, Italic, Underline +*.colorBD: #9a90a7 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-sea-dark b/assets/colors/schemes/base2tone-sea-dark new file mode 100644 index 0000000..940255f --- /dev/null +++ b/assets/colors/schemes/base2tone-sea-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #a1aab5 +*.background: #1d262f +*.cursorColor: #067953 +! +! Black +*.color0: #1d262f +*.color8: #4a5f78 +! +! Red +*.color1: #34659d +*.color9: #14e19d +! +! Green +*.color2: #0fc78a +*.color10: #27323f +! +! Yellow +*.color3: #47ebb4 +*.color11: #405368 +! +! Blue +*.color4: #57718e +*.color12: #738191 +! +! Magenta +*.color5: #0fc78a +*.color13: #afd4fe +! +! Cyan +*.color6: #6e9bcf +*.color14: #0db57d +! +! White +*.color7: #a1aab5 +*.color15: #ebf4ff +! +! Bold, Italic, Underline +*.colorBD: #a1aab5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/base2tone-space-dark b/assets/colors/schemes/base2tone-space-dark new file mode 100644 index 0000000..bfb476b --- /dev/null +++ b/assets/colors/schemes/base2tone-space-dark @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xrecources.py +! +*.foreground: #a1a1b5 +*.background: #24242e +*.cursorColor: #b25424 +! +! Black +*.color0: #24242e +*.color8: #5b5b76 +! +! Red +*.color1: #7676f4 +*.color9: #f37b3f +! +! Green +*.color2: #ec7336 +*.color10: #333342 +! +! Yellow +*.color3: #fe8c52 +*.color11: #515167 +! +! Blue +*.color4: #767693 +*.color12: #737391 +! +! Magenta +*.color5: #ec7336 +*.color13: #cecee3 +! +! Cyan +*.color6: #8a8aad +*.color14: #e66e33 +! +! White +*.color7: #a1a1b5 +*.color15: #ebebff +! +! Bold, Italic, Underline +*.colorBD: #a1a1b5 +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/deep b/assets/colors/schemes/deep new file mode 100644 index 0000000..db54c45 --- /dev/null +++ b/assets/colors/schemes/deep @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #cdcdcd +*.background: #000000 +*.cursorColor: #d0d0d0 +! +! Black +*.color0: #000000 +*.color8: #535353 +! +! Red +*.color1: #d11600 +*.color9: #f4152c +! +! Green +*.color2: #37c32c +*.color10: #01ea10 +! +! Yellow +*.color3: #e3c421 +*.color11: #ffee1d +! +! Blue +*.color4: #5c6bfd +*.color12: #8cb0f8 +! +! Magenta +*.color5: #dd5be5 +*.color13: #e056f5 +! +! Cyan +*.color6: #6eb4f2 +*.color14: #67ecff +! +! White +*.color7: #e0e0e0 +*.color15: #f4f4f4 +! +! Bold, Italic, Underline +*.colorBD: #eeeeee +!*.colorIT: +!*.colorUL: diff --git a/assets/colors/schemes/idleToes b/assets/colors/schemes/idleToes new file mode 100644 index 0000000..a61095f --- /dev/null +++ b/assets/colors/schemes/idleToes @@ -0,0 +1,44 @@ +! +! Generated with : +! XRDB2Xreources.py +! +*.foreground: #ffffff +*.background: #323232 +*.cursorColor: #d6d6d6 +! +! Black +*.color0: #323232 +*.color8: #535353 +! +! Red +*.color1: #d25252 +*.color9: #f07070 +! +! Green +*.color2: #7fe173 +*.color10: #9dff91 +! +! Yellow +*.color3: #ffc66d +*.color11: #ffe48b +! +! Blue +*.color4: #4099ff +*.color12: #5eb7f7 +! +! Magenta +*.color5: #f680ff +*.color13: #ff9dff +! +! Cyan +*.color6: #bed6ff +*.color14: #dcf4ff +! +! White +*.color7: #eeeeec +*.color15: #ffffff +! +! Bold, Italic, Underline +*.colorBD: #ffffa9 +!*.colorIT: +!*.colorUL: diff --git a/assets/fonts/Meslo_LG_L_Bold_Italic_for_Powerline.ttf b/assets/fonts/Meslo_LG_L_Bold_Italic_for_Powerline.ttf new file mode 100644 index 0000000..92232a9 Binary files /dev/null and b/assets/fonts/Meslo_LG_L_Bold_Italic_for_Powerline.ttf differ diff --git a/assets/fonts/Meslo_LG_L_Bold_for_Powerline.ttf b/assets/fonts/Meslo_LG_L_Bold_for_Powerline.ttf new file mode 100644 index 0000000..56cd314 Binary files /dev/null and b/assets/fonts/Meslo_LG_L_Bold_for_Powerline.ttf differ diff --git a/assets/fonts/Meslo_LG_L_Italic_for_Powerline.ttf b/assets/fonts/Meslo_LG_L_Italic_for_Powerline.ttf new file mode 100644 index 0000000..b10408f Binary files /dev/null and b/assets/fonts/Meslo_LG_L_Italic_for_Powerline.ttf differ diff --git a/assets/fonts/Meslo_LG_L_Regular_for_Powerline.ttf b/assets/fonts/Meslo_LG_L_Regular_for_Powerline.ttf new file mode 100644 index 0000000..651689a Binary files /dev/null and b/assets/fonts/Meslo_LG_L_Regular_for_Powerline.ttf differ diff --git a/assets/icons/alma.svg b/assets/icons/alma.svg new file mode 100644 index 0000000..1955347 --- /dev/null +++ b/assets/icons/alma.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/alpine.svg b/assets/icons/alpine.svg new file mode 100644 index 0000000..2bc39b7 --- /dev/null +++ b/assets/icons/alpine.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/clink.svg b/assets/icons/clink.svg new file mode 100644 index 0000000..34a6d96 --- /dev/null +++ b/assets/icons/clink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/cmd.svg b/assets/icons/cmd.svg new file mode 100644 index 0000000..8665724 --- /dev/null +++ b/assets/icons/cmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/cmder-powershell.svg b/assets/icons/cmder-powershell.svg new file mode 100644 index 0000000..e0e1d3a --- /dev/null +++ b/assets/icons/cmder-powershell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/cmder.svg b/assets/icons/cmder.svg new file mode 100644 index 0000000..75e6370 --- /dev/null +++ b/assets/icons/cmder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/cygwin.svg b/assets/icons/cygwin.svg new file mode 100644 index 0000000..48ae9f0 --- /dev/null +++ b/assets/icons/cygwin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/debian.svg b/assets/icons/debian.svg new file mode 100644 index 0000000..e459194 --- /dev/null +++ b/assets/icons/debian.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/docker.svg b/assets/icons/docker.svg new file mode 100644 index 0000000..eb5c7ba --- /dev/null +++ b/assets/icons/docker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/git-bash.svg b/assets/icons/git-bash.svg new file mode 100644 index 0000000..1004781 --- /dev/null +++ b/assets/icons/git-bash.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/kali.svg b/assets/icons/kali.svg new file mode 100644 index 0000000..d73f67e --- /dev/null +++ b/assets/icons/kali.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/linux.svg b/assets/icons/linux.svg new file mode 100644 index 0000000..ba60f61 --- /dev/null +++ b/assets/icons/linux.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/msys2.svg b/assets/icons/msys2.svg new file mode 100644 index 0000000..fe12b4e --- /dev/null +++ b/assets/icons/msys2.svg @@ -0,0 +1,25 @@ + + + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/open-euler.svg b/assets/icons/open-euler.svg new file mode 100644 index 0000000..a096638 --- /dev/null +++ b/assets/icons/open-euler.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/oracle-linux.svg b/assets/icons/oracle-linux.svg new file mode 100644 index 0000000..0528eb2 --- /dev/null +++ b/assets/icons/oracle-linux.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/powershell-core.svg b/assets/icons/powershell-core.svg new file mode 100644 index 0000000..044e282 --- /dev/null +++ b/assets/icons/powershell-core.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/powershell.svg b/assets/icons/powershell.svg new file mode 100644 index 0000000..5bef633 --- /dev/null +++ b/assets/icons/powershell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/suse.svg b/assets/icons/suse.svg new file mode 100644 index 0000000..e3d0a27 --- /dev/null +++ b/assets/icons/suse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/ubuntu.svg b/assets/icons/ubuntu.svg new file mode 100644 index 0000000..228cdfe --- /dev/null +++ b/assets/icons/ubuntu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/vs2017.svg b/assets/icons/vs2017.svg new file mode 100644 index 0000000..421fe0f --- /dev/null +++ b/assets/icons/vs2017.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/vs2019.svg b/assets/icons/vs2019.svg new file mode 100644 index 0000000..3fd566d --- /dev/null +++ b/assets/icons/vs2019.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/vs2022.svg b/assets/icons/vs2022.svg new file mode 100644 index 0000000..699f27b --- /dev/null +++ b/assets/icons/vs2022.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/ic_chrome_close.png b/assets/images/ic_chrome_close.png new file mode 100644 index 0000000..1949491 Binary files /dev/null and b/assets/images/ic_chrome_close.png differ diff --git a/assets/images/ic_chrome_maximize.png b/assets/images/ic_chrome_maximize.png new file mode 100644 index 0000000..672e9e4 Binary files /dev/null and b/assets/images/ic_chrome_maximize.png differ diff --git a/assets/images/ic_chrome_minimize.png b/assets/images/ic_chrome_minimize.png new file mode 100644 index 0000000..05534b4 Binary files /dev/null and b/assets/images/ic_chrome_minimize.png differ diff --git a/assets/images/ic_chrome_unmaximize.png b/assets/images/ic_chrome_unmaximize.png new file mode 100644 index 0000000..52b8f4e Binary files /dev/null and b/assets/images/ic_chrome_unmaximize.png differ diff --git a/assets/terminal.png b/assets/terminal.png new file mode 100644 index 0000000..68bbdbe Binary files /dev/null and b/assets/terminal.png differ diff --git a/assets/terminal.svg b/assets/terminal.svg new file mode 100644 index 0000000..1f9e287 --- /dev/null +++ b/assets/terminal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/distribute_options.yaml b/distribute_options.yaml new file mode 100644 index 0000000..db77bdb --- /dev/null +++ b/distribute_options.yaml @@ -0,0 +1,37 @@ +output: dist/ +artifact_name: "{{name}}-{{platform}}{{#flavor}}-{{flavor}}{{/flavor}}{{#channel}}-{{channel}}{{/channel}}-{{version}}{{#is_installer}}-setup{{/is_installer}}.{{ext}}" +releases: + - name: macos + jobs: + - name: archive + package: + platform: macos + target: zip + obfuscate: + split-debug-info: symbols + - name: app + package: + platform: macos + target: dmg + obfuscate: + split-debug-info: symbols + - name: windows + jobs: + - name: exe + package: + platform: windows + target: exe + obfuscate: + split-debug-info: symbols + - name: zip + package: + platform: windows + target: zip + obfuscate: + split-debug-info: symbols + - name: msix + package: + platform: windows + target: msix + obfuscate: + split-debug-info: symbols diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml new file mode 100644 index 0000000..932aa11 --- /dev/null +++ b/flutter_launcher_icons.yaml @@ -0,0 +1,9 @@ +flutter_launcher_icons: + image_path: "assets/terminal.png" + windows: + generate: true + image_path: "assets/terminal.png" + icon_size: 48 # min:48, max:256, default: 48 + macos: + generate: true + image_path: "assets/terminal.png" diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..65ac504 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,5 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: SS.dart +output-class: SS +nullable-getter: false \ No newline at end of file diff --git a/lib/bloc/app_config_cubit.dart b/lib/bloc/app_config_cubit.dart new file mode 100644 index 0000000..8ac601a --- /dev/null +++ b/lib/bloc/app_config_cubit.dart @@ -0,0 +1,215 @@ +import 'dart:convert'; +import 'dart:ui'; + +import 'package:bloc/bloc.dart'; +import 'package:flutter/services.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:xterm/xterm.dart'; + + +part 'app_config_state.dart'; + +part 'app_config_cubit.freezed.dart'; + +class AppConfigCubit extends Cubit { + AppConfigCubit({Locale? startLocal}) + : super(AppConfigState.initial(locale: startLocal)); + + void setCurrentColorScheme(String name) { + var theme = state.colorSchemes[name]; + if (theme != null) { + emit(state.copyWith( + currentColor: theme, + currentColorName: name, + )); + } + SharedPreferences.getInstance() + .then((value) => value.setString("color", name)); + } + + Future init() async { + emit(state.copyWith(colorSchemes: { + "default": TerminalThemes.defaultTheme, + "whiteOnBlack": TerminalThemes.whiteOnBlack + })); + var colors = await _loadColorSchemes(); + var sp = await SharedPreferences.getInstance(); + var color = sp.getString("color"); + var theme = colors[color]; + emit(state.copyWith( + colorSchemes: colors, + currentColor: theme ?? TerminalThemes.defaultTheme, + currentColorName: color ?? "default", + )); + } + + Future> _loadColorSchemes() async { + var colors = { + "default": TerminalThemes.defaultTheme, + "whiteOnBlack": TerminalThemes.whiteOnBlack + }; + final manifestJson = await rootBundle.loadString('AssetManifest.json'); + final keys = json + .decode(manifestJson) + .keys + .where((String key) => key.startsWith('assets/colors/schemes')); + for (var k in keys) { + var name = k.substring(k.lastIndexOf("/") + 1); + var lines = await rootBundle + .loadString(k) + .then>((value) => value.split("\n")); + var variables = {}; + List.from(lines) + .where((element) => element.startsWith("#define")) + .map((event) => event.split(" ")) + .map((event) => event.map((e) => e.trim()).toList()) + .map((event) => {event[1]: event[2]}) + .forEach((element) { + if (element.isNotEmpty) { + for (var element in element.entries) { + variables[element.key] = element.value; + } + } + }); + var values = {}; + List.from(lines) + .where((x) => x.startsWith('*.')) + .map((x) => x.substring(2)) + .map>((x) => x.split(':').map((v) => v.trim()).toList()) + .forEach((element) { + if (element.length > 1) { + if (variables.isNotEmpty) { + var newV = variables[element[1]]; + values[element[0]] = newV ?? element[1]; + } else { + values[element[0]] = element[1]; + } + } + }); + // print(values); + Color cursorColor = TerminalThemes.defaultTheme.cursor; + Color selection = TerminalThemes.defaultTheme.selection; + Color foreground = TerminalThemes.defaultTheme.foreground; + Color background = TerminalThemes.defaultTheme.background; + + Color black = TerminalThemes.defaultTheme.black; + Color red = TerminalThemes.defaultTheme.red; + Color green = TerminalThemes.defaultTheme.green; + Color yellow = TerminalThemes.defaultTheme.yellow; + Color blue = TerminalThemes.defaultTheme.blue; + Color magenta = TerminalThemes.defaultTheme.magenta; + Color cyan = TerminalThemes.defaultTheme.cyan; + Color white = TerminalThemes.defaultTheme.white; + + Color brightBlack = TerminalThemes.defaultTheme.brightBlack; + Color brightRed = TerminalThemes.defaultTheme.brightRed; + Color brightGreen = TerminalThemes.defaultTheme.brightGreen; + Color brightYellow = TerminalThemes.defaultTheme.brightYellow; + Color brightBlue = TerminalThemes.defaultTheme.brightBlue; + Color brightMagenta = TerminalThemes.defaultTheme.brightMagenta; + Color brightCyan = TerminalThemes.defaultTheme.brightCyan; + Color brightWhite = TerminalThemes.defaultTheme.brightWhite; + + Color searchHitBackground = + TerminalThemes.defaultTheme.searchHitBackground; + Color searchHitBackgroundCurrent = + TerminalThemes.defaultTheme.searchHitBackgroundCurrent; + Color searchHitForeground = + TerminalThemes.defaultTheme.searchHitForeground; + for (var e in values.entries) { + var color = Color(int.parse(e.value.replaceFirst("#", ""), radix: 16)) + .withAlpha(255); + if (e.key == "foreground") { + foreground = color; + } else if (e.key == "background") { + background = color; + } else if (e.key == "cursorColor") { + cursorColor = color; + } else if (e.key == "colorBD") { + } else if (e.key == "color0") { + black = color; + } else if (e.key == "color1") { + red = color; + } else if (e.key == "color2") { + green = color; + } else if (e.key == "color3") { + yellow = color; + } else if (e.key == "color4") { + blue = color; + } else if (e.key == "color5") { + magenta = color; + } else if (e.key == "color6") { + cyan = color; + } else if (e.key == "color7") { + white = color; + } else if (e.key == "color8") { + brightBlack = color; + } else if (e.key == "color9") { + brightRed = color; + } else if (e.key == "color10") { + brightGreen = color; + } else if (e.key == "color11") { + brightYellow = color; + } else if (e.key == "color12") { + brightBlue = color; + } else if (e.key == "color13") { + brightMagenta = color; + } else if (e.key == "color14") { + brightCyan = color; + } else if (e.key == "color15") { + white = color; + } + } + colors[name] = TerminalTheme( + cursor: cursorColor, + selection: selection, + foreground: foreground, + background: background, + black: background, + red: red, + green: green, + yellow: yellow, + blue: blue, + magenta: magenta, + cyan: cyan, + white: white, + brightBlack: brightBlack, + brightRed: brightRed, + brightGreen: brightGreen, + brightYellow: brightYellow, + brightBlue: brightBlue, + brightMagenta: brightMagenta, + brightCyan: brightCyan, + brightWhite: brightWhite, + searchHitBackground: searchHitBackground, + searchHitBackgroundCurrent: searchHitBackgroundCurrent, + searchHitForeground: searchHitForeground, + ); + } + return colors; + } + + void showFPS(bool show) { + if (state.showFPS != show) { + SharedPreferences.getInstance().then((value) { + value.setBool("showFPS", show); + }); + emit(state.copyWith(showFPS: show)); + } + } + + void setLocal(Locale locale) { + SharedPreferences.getInstance().then((value) { + value.setString("lang", locale.toString()); + }); + if (state.locale != locale) { + emit(state.copyWith(locale: locale)); + } + } + + void clearLocal() { + SharedPreferences.getInstance().then((value) => value.remove("lang")); + emit(state.copyWith(locale: null)); + } +} diff --git a/lib/bloc/app_config_cubit.freezed.dart b/lib/bloc/app_config_cubit.freezed.dart new file mode 100644 index 0000000..902c78c --- /dev/null +++ b/lib/bloc/app_config_cubit.freezed.dart @@ -0,0 +1,237 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'app_config_cubit.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$AppConfigState { + Locale? get locale => throw _privateConstructorUsedError; + Map get colorSchemes => + throw _privateConstructorUsedError; + TerminalTheme get currentColor => throw _privateConstructorUsedError; + String get currentColorName => throw _privateConstructorUsedError; + bool get showFPS => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $AppConfigStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AppConfigStateCopyWith<$Res> { + factory $AppConfigStateCopyWith( + AppConfigState value, $Res Function(AppConfigState) then) = + _$AppConfigStateCopyWithImpl<$Res, AppConfigState>; + @useResult + $Res call( + {Locale? locale, + Map colorSchemes, + TerminalTheme currentColor, + String currentColorName, + bool showFPS}); +} + +/// @nodoc +class _$AppConfigStateCopyWithImpl<$Res, $Val extends AppConfigState> + implements $AppConfigStateCopyWith<$Res> { + _$AppConfigStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? colorSchemes = null, + Object? currentColor = null, + Object? currentColorName = null, + Object? showFPS = null, + }) { + return _then(_value.copyWith( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale?, + colorSchemes: null == colorSchemes + ? _value.colorSchemes + : colorSchemes // ignore: cast_nullable_to_non_nullable + as Map, + currentColor: null == currentColor + ? _value.currentColor + : currentColor // ignore: cast_nullable_to_non_nullable + as TerminalTheme, + currentColorName: null == currentColorName + ? _value.currentColorName + : currentColorName // ignore: cast_nullable_to_non_nullable + as String, + showFPS: null == showFPS + ? _value.showFPS + : showFPS // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_AppConfigStateCopyWith<$Res> + implements $AppConfigStateCopyWith<$Res> { + factory _$$_AppConfigStateCopyWith( + _$_AppConfigState value, $Res Function(_$_AppConfigState) then) = + __$$_AppConfigStateCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Locale? locale, + Map colorSchemes, + TerminalTheme currentColor, + String currentColorName, + bool showFPS}); +} + +/// @nodoc +class __$$_AppConfigStateCopyWithImpl<$Res> + extends _$AppConfigStateCopyWithImpl<$Res, _$_AppConfigState> + implements _$$_AppConfigStateCopyWith<$Res> { + __$$_AppConfigStateCopyWithImpl( + _$_AppConfigState _value, $Res Function(_$_AppConfigState) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? colorSchemes = null, + Object? currentColor = null, + Object? currentColorName = null, + Object? showFPS = null, + }) { + return _then(_$_AppConfigState( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale?, + colorSchemes: null == colorSchemes + ? _value._colorSchemes + : colorSchemes // ignore: cast_nullable_to_non_nullable + as Map, + currentColor: null == currentColor + ? _value.currentColor + : currentColor // ignore: cast_nullable_to_non_nullable + as TerminalTheme, + currentColorName: null == currentColorName + ? _value.currentColorName + : currentColorName // ignore: cast_nullable_to_non_nullable + as String, + showFPS: null == showFPS + ? _value.showFPS + : showFPS // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$_AppConfigState implements _AppConfigState { + const _$_AppConfigState( + {this.locale, + final Map colorSchemes = const {}, + this.currentColor = TerminalThemes.defaultTheme, + this.currentColorName = "default", + this.showFPS = false}) + : _colorSchemes = colorSchemes; + + @override + final Locale? locale; + final Map _colorSchemes; + @override + @JsonKey() + Map get colorSchemes { + if (_colorSchemes is EqualUnmodifiableMapView) return _colorSchemes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_colorSchemes); + } + + @override + @JsonKey() + final TerminalTheme currentColor; + @override + @JsonKey() + final String currentColorName; + @override + @JsonKey() + final bool showFPS; + + @override + String toString() { + return 'AppConfigState(locale: $locale, colorSchemes: $colorSchemes, currentColor: $currentColor, currentColorName: $currentColorName, showFPS: $showFPS)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_AppConfigState && + (identical(other.locale, locale) || other.locale == locale) && + const DeepCollectionEquality() + .equals(other._colorSchemes, _colorSchemes) && + (identical(other.currentColor, currentColor) || + other.currentColor == currentColor) && + (identical(other.currentColorName, currentColorName) || + other.currentColorName == currentColorName) && + (identical(other.showFPS, showFPS) || other.showFPS == showFPS)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + locale, + const DeepCollectionEquality().hash(_colorSchemes), + currentColor, + currentColorName, + showFPS); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AppConfigStateCopyWith<_$_AppConfigState> get copyWith => + __$$_AppConfigStateCopyWithImpl<_$_AppConfigState>(this, _$identity); +} + +abstract class _AppConfigState implements AppConfigState { + const factory _AppConfigState( + {final Locale? locale, + final Map colorSchemes, + final TerminalTheme currentColor, + final String currentColorName, + final bool showFPS}) = _$_AppConfigState; + + @override + Locale? get locale; + @override + Map get colorSchemes; + @override + TerminalTheme get currentColor; + @override + String get currentColorName; + @override + bool get showFPS; + @override + @JsonKey(ignore: true) + _$$_AppConfigStateCopyWith<_$_AppConfigState> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/bloc/app_config_state.dart b/lib/bloc/app_config_state.dart new file mode 100644 index 0000000..b3c92b3 --- /dev/null +++ b/lib/bloc/app_config_state.dart @@ -0,0 +1,20 @@ +part of 'app_config_cubit.dart'; + +@freezed +class AppConfigState with _$AppConfigState { + const factory AppConfigState({ + Locale? locale, + @Default({}) Map colorSchemes, + @Default(TerminalThemes.defaultTheme) TerminalTheme currentColor, + @Default("default") String currentColorName, + @Default(false) bool showFPS, + }) = _AppConfigState; + + factory AppConfigState.initial({Locale? locale, bool showFPS = false}) => + AppConfigState( + colorSchemes: {}, + locale: locale, + currentColorName: "default", + currentColor: TerminalThemes.defaultTheme, + showFPS: showFPS); +} diff --git a/lib/bloc/home_tab_bloc.dart b/lib/bloc/home_tab_bloc.dart new file mode 100644 index 0000000..49abc36 --- /dev/null +++ b/lib/bloc/home_tab_bloc.dart @@ -0,0 +1,52 @@ +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:fterm/model/tab_item.dart'; + +part 'home_tab_event.dart'; + +part 'home_tab_state.dart'; + +part 'home_tab_bloc.freezed.dart'; + +class HomeTabBloc extends Bloc { + HomeTabBloc({TabItem? init}) : super(HomeTabState.initial(init: init)) { + on((event, emit) { + event.map( + add: (e) { + List tabs = List.from(state.tabs); + tabs.add(e.tab); + emit(state.copyWith(tabs: tabs, currentIndex: tabs.length - 1)); + }, + remove: (e) { + List tabs = List.from(state.tabs); + tabs.remove(e.tab); + int currentIndex = state.currentIndex; + if (currentIndex > 0) currentIndex--; + emit(state.copyWith(tabs: tabs, currentIndex: currentIndex)); + }, + change: (e) { + if (e.index >= 0 && e.index < state.tabs.length) { + emit(state.copyWith(currentIndex: e.index)); + } + }, + reorder: (e) { + int oldIndex = e.oldIndex; + int newIndex = e.newIndex; + int currentIndex = state.currentIndex; + List tabs = List.from(state.tabs); + if (oldIndex < newIndex) { + newIndex -= 1; + } + final item = tabs.removeAt(oldIndex); + tabs.insert(newIndex, item); + if (currentIndex == newIndex) { + currentIndex = oldIndex; + } else if (currentIndex == oldIndex) { + currentIndex = newIndex; + } + emit(state.copyWith(tabs: tabs, currentIndex: currentIndex)); + }, + ); + }); + } +} diff --git a/lib/bloc/home_tab_bloc.freezed.dart b/lib/bloc/home_tab_bloc.freezed.dart new file mode 100644 index 0000000..166b6ab --- /dev/null +++ b/lib/bloc/home_tab_bloc.freezed.dart @@ -0,0 +1,815 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'home_tab_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$HomeTabEvent { + @optionalTypeArgs + TResult when({ + required TResult Function(TabItem tab) add, + required TResult Function(TabItem tab) remove, + required TResult Function(int index) change, + required TResult Function(int oldIndex, int newIndex) reorder, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(TabItem tab)? add, + TResult? Function(TabItem tab)? remove, + TResult? Function(int index)? change, + TResult? Function(int oldIndex, int newIndex)? reorder, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(TabItem tab)? add, + TResult Function(TabItem tab)? remove, + TResult Function(int index)? change, + TResult Function(int oldIndex, int newIndex)? reorder, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Add value) add, + required TResult Function(_Remove value) remove, + required TResult Function(_Change value) change, + required TResult Function(_Reorder value) reorder, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Add value)? add, + TResult? Function(_Remove value)? remove, + TResult? Function(_Change value)? change, + TResult? Function(_Reorder value)? reorder, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Add value)? add, + TResult Function(_Remove value)? remove, + TResult Function(_Change value)? change, + TResult Function(_Reorder value)? reorder, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $HomeTabEventCopyWith<$Res> { + factory $HomeTabEventCopyWith( + HomeTabEvent value, $Res Function(HomeTabEvent) then) = + _$HomeTabEventCopyWithImpl<$Res, HomeTabEvent>; +} + +/// @nodoc +class _$HomeTabEventCopyWithImpl<$Res, $Val extends HomeTabEvent> + implements $HomeTabEventCopyWith<$Res> { + _$HomeTabEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_AddCopyWith<$Res> { + factory _$$_AddCopyWith(_$_Add value, $Res Function(_$_Add) then) = + __$$_AddCopyWithImpl<$Res>; + @useResult + $Res call({TabItem tab}); +} + +/// @nodoc +class __$$_AddCopyWithImpl<$Res> + extends _$HomeTabEventCopyWithImpl<$Res, _$_Add> + implements _$$_AddCopyWith<$Res> { + __$$_AddCopyWithImpl(_$_Add _value, $Res Function(_$_Add) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? tab = null, + }) { + return _then(_$_Add( + null == tab + ? _value.tab + : tab // ignore: cast_nullable_to_non_nullable + as TabItem, + )); + } +} + +/// @nodoc + +class _$_Add implements _Add { + const _$_Add(this.tab); + + @override + final TabItem tab; + + @override + String toString() { + return 'HomeTabEvent.add(tab: $tab)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Add && + (identical(other.tab, tab) || other.tab == tab)); + } + + @override + int get hashCode => Object.hash(runtimeType, tab); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AddCopyWith<_$_Add> get copyWith => + __$$_AddCopyWithImpl<_$_Add>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(TabItem tab) add, + required TResult Function(TabItem tab) remove, + required TResult Function(int index) change, + required TResult Function(int oldIndex, int newIndex) reorder, + }) { + return add(tab); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(TabItem tab)? add, + TResult? Function(TabItem tab)? remove, + TResult? Function(int index)? change, + TResult? Function(int oldIndex, int newIndex)? reorder, + }) { + return add?.call(tab); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(TabItem tab)? add, + TResult Function(TabItem tab)? remove, + TResult Function(int index)? change, + TResult Function(int oldIndex, int newIndex)? reorder, + required TResult orElse(), + }) { + if (add != null) { + return add(tab); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Add value) add, + required TResult Function(_Remove value) remove, + required TResult Function(_Change value) change, + required TResult Function(_Reorder value) reorder, + }) { + return add(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Add value)? add, + TResult? Function(_Remove value)? remove, + TResult? Function(_Change value)? change, + TResult? Function(_Reorder value)? reorder, + }) { + return add?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Add value)? add, + TResult Function(_Remove value)? remove, + TResult Function(_Change value)? change, + TResult Function(_Reorder value)? reorder, + required TResult orElse(), + }) { + if (add != null) { + return add(this); + } + return orElse(); + } +} + +abstract class _Add implements HomeTabEvent { + const factory _Add(final TabItem tab) = _$_Add; + + TabItem get tab; + @JsonKey(ignore: true) + _$$_AddCopyWith<_$_Add> get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_RemoveCopyWith<$Res> { + factory _$$_RemoveCopyWith(_$_Remove value, $Res Function(_$_Remove) then) = + __$$_RemoveCopyWithImpl<$Res>; + @useResult + $Res call({TabItem tab}); +} + +/// @nodoc +class __$$_RemoveCopyWithImpl<$Res> + extends _$HomeTabEventCopyWithImpl<$Res, _$_Remove> + implements _$$_RemoveCopyWith<$Res> { + __$$_RemoveCopyWithImpl(_$_Remove _value, $Res Function(_$_Remove) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? tab = null, + }) { + return _then(_$_Remove( + null == tab + ? _value.tab + : tab // ignore: cast_nullable_to_non_nullable + as TabItem, + )); + } +} + +/// @nodoc + +class _$_Remove implements _Remove { + const _$_Remove(this.tab); + + @override + final TabItem tab; + + @override + String toString() { + return 'HomeTabEvent.remove(tab: $tab)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Remove && + (identical(other.tab, tab) || other.tab == tab)); + } + + @override + int get hashCode => Object.hash(runtimeType, tab); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_RemoveCopyWith<_$_Remove> get copyWith => + __$$_RemoveCopyWithImpl<_$_Remove>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(TabItem tab) add, + required TResult Function(TabItem tab) remove, + required TResult Function(int index) change, + required TResult Function(int oldIndex, int newIndex) reorder, + }) { + return remove(tab); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(TabItem tab)? add, + TResult? Function(TabItem tab)? remove, + TResult? Function(int index)? change, + TResult? Function(int oldIndex, int newIndex)? reorder, + }) { + return remove?.call(tab); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(TabItem tab)? add, + TResult Function(TabItem tab)? remove, + TResult Function(int index)? change, + TResult Function(int oldIndex, int newIndex)? reorder, + required TResult orElse(), + }) { + if (remove != null) { + return remove(tab); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Add value) add, + required TResult Function(_Remove value) remove, + required TResult Function(_Change value) change, + required TResult Function(_Reorder value) reorder, + }) { + return remove(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Add value)? add, + TResult? Function(_Remove value)? remove, + TResult? Function(_Change value)? change, + TResult? Function(_Reorder value)? reorder, + }) { + return remove?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Add value)? add, + TResult Function(_Remove value)? remove, + TResult Function(_Change value)? change, + TResult Function(_Reorder value)? reorder, + required TResult orElse(), + }) { + if (remove != null) { + return remove(this); + } + return orElse(); + } +} + +abstract class _Remove implements HomeTabEvent { + const factory _Remove(final TabItem tab) = _$_Remove; + + TabItem get tab; + @JsonKey(ignore: true) + _$$_RemoveCopyWith<_$_Remove> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_ChangeCopyWith<$Res> { + factory _$$_ChangeCopyWith(_$_Change value, $Res Function(_$_Change) then) = + __$$_ChangeCopyWithImpl<$Res>; + @useResult + $Res call({int index}); +} + +/// @nodoc +class __$$_ChangeCopyWithImpl<$Res> + extends _$HomeTabEventCopyWithImpl<$Res, _$_Change> + implements _$$_ChangeCopyWith<$Res> { + __$$_ChangeCopyWithImpl(_$_Change _value, $Res Function(_$_Change) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? index = null, + }) { + return _then(_$_Change( + null == index + ? _value.index + : index // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$_Change implements _Change { + const _$_Change(this.index); + + @override + final int index; + + @override + String toString() { + return 'HomeTabEvent.change(index: $index)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Change && + (identical(other.index, index) || other.index == index)); + } + + @override + int get hashCode => Object.hash(runtimeType, index); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_ChangeCopyWith<_$_Change> get copyWith => + __$$_ChangeCopyWithImpl<_$_Change>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(TabItem tab) add, + required TResult Function(TabItem tab) remove, + required TResult Function(int index) change, + required TResult Function(int oldIndex, int newIndex) reorder, + }) { + return change(index); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(TabItem tab)? add, + TResult? Function(TabItem tab)? remove, + TResult? Function(int index)? change, + TResult? Function(int oldIndex, int newIndex)? reorder, + }) { + return change?.call(index); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(TabItem tab)? add, + TResult Function(TabItem tab)? remove, + TResult Function(int index)? change, + TResult Function(int oldIndex, int newIndex)? reorder, + required TResult orElse(), + }) { + if (change != null) { + return change(index); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Add value) add, + required TResult Function(_Remove value) remove, + required TResult Function(_Change value) change, + required TResult Function(_Reorder value) reorder, + }) { + return change(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Add value)? add, + TResult? Function(_Remove value)? remove, + TResult? Function(_Change value)? change, + TResult? Function(_Reorder value)? reorder, + }) { + return change?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Add value)? add, + TResult Function(_Remove value)? remove, + TResult Function(_Change value)? change, + TResult Function(_Reorder value)? reorder, + required TResult orElse(), + }) { + if (change != null) { + return change(this); + } + return orElse(); + } +} + +abstract class _Change implements HomeTabEvent { + const factory _Change(final int index) = _$_Change; + + int get index; + @JsonKey(ignore: true) + _$$_ChangeCopyWith<_$_Change> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_ReorderCopyWith<$Res> { + factory _$$_ReorderCopyWith( + _$_Reorder value, $Res Function(_$_Reorder) then) = + __$$_ReorderCopyWithImpl<$Res>; + @useResult + $Res call({int oldIndex, int newIndex}); +} + +/// @nodoc +class __$$_ReorderCopyWithImpl<$Res> + extends _$HomeTabEventCopyWithImpl<$Res, _$_Reorder> + implements _$$_ReorderCopyWith<$Res> { + __$$_ReorderCopyWithImpl(_$_Reorder _value, $Res Function(_$_Reorder) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? oldIndex = null, + Object? newIndex = null, + }) { + return _then(_$_Reorder( + null == oldIndex + ? _value.oldIndex + : oldIndex // ignore: cast_nullable_to_non_nullable + as int, + null == newIndex + ? _value.newIndex + : newIndex // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$_Reorder implements _Reorder { + const _$_Reorder(this.oldIndex, this.newIndex); + + @override + final int oldIndex; + @override + final int newIndex; + + @override + String toString() { + return 'HomeTabEvent.reorder(oldIndex: $oldIndex, newIndex: $newIndex)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Reorder && + (identical(other.oldIndex, oldIndex) || + other.oldIndex == oldIndex) && + (identical(other.newIndex, newIndex) || + other.newIndex == newIndex)); + } + + @override + int get hashCode => Object.hash(runtimeType, oldIndex, newIndex); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_ReorderCopyWith<_$_Reorder> get copyWith => + __$$_ReorderCopyWithImpl<_$_Reorder>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(TabItem tab) add, + required TResult Function(TabItem tab) remove, + required TResult Function(int index) change, + required TResult Function(int oldIndex, int newIndex) reorder, + }) { + return reorder(oldIndex, newIndex); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(TabItem tab)? add, + TResult? Function(TabItem tab)? remove, + TResult? Function(int index)? change, + TResult? Function(int oldIndex, int newIndex)? reorder, + }) { + return reorder?.call(oldIndex, newIndex); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(TabItem tab)? add, + TResult Function(TabItem tab)? remove, + TResult Function(int index)? change, + TResult Function(int oldIndex, int newIndex)? reorder, + required TResult orElse(), + }) { + if (reorder != null) { + return reorder(oldIndex, newIndex); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Add value) add, + required TResult Function(_Remove value) remove, + required TResult Function(_Change value) change, + required TResult Function(_Reorder value) reorder, + }) { + return reorder(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Add value)? add, + TResult? Function(_Remove value)? remove, + TResult? Function(_Change value)? change, + TResult? Function(_Reorder value)? reorder, + }) { + return reorder?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Add value)? add, + TResult Function(_Remove value)? remove, + TResult Function(_Change value)? change, + TResult Function(_Reorder value)? reorder, + required TResult orElse(), + }) { + if (reorder != null) { + return reorder(this); + } + return orElse(); + } +} + +abstract class _Reorder implements HomeTabEvent { + const factory _Reorder(final int oldIndex, final int newIndex) = _$_Reorder; + + int get oldIndex; + int get newIndex; + @JsonKey(ignore: true) + _$$_ReorderCopyWith<_$_Reorder> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$HomeTabState { + List get tabs => throw _privateConstructorUsedError; + int get currentIndex => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $HomeTabStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $HomeTabStateCopyWith<$Res> { + factory $HomeTabStateCopyWith( + HomeTabState value, $Res Function(HomeTabState) then) = + _$HomeTabStateCopyWithImpl<$Res, HomeTabState>; + @useResult + $Res call({List tabs, int currentIndex}); +} + +/// @nodoc +class _$HomeTabStateCopyWithImpl<$Res, $Val extends HomeTabState> + implements $HomeTabStateCopyWith<$Res> { + _$HomeTabStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? tabs = null, + Object? currentIndex = null, + }) { + return _then(_value.copyWith( + tabs: null == tabs + ? _value.tabs + : tabs // ignore: cast_nullable_to_non_nullable + as List, + currentIndex: null == currentIndex + ? _value.currentIndex + : currentIndex // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_HomeTabStateCopyWith<$Res> + implements $HomeTabStateCopyWith<$Res> { + factory _$$_HomeTabStateCopyWith( + _$_HomeTabState value, $Res Function(_$_HomeTabState) then) = + __$$_HomeTabStateCopyWithImpl<$Res>; + @override + @useResult + $Res call({List tabs, int currentIndex}); +} + +/// @nodoc +class __$$_HomeTabStateCopyWithImpl<$Res> + extends _$HomeTabStateCopyWithImpl<$Res, _$_HomeTabState> + implements _$$_HomeTabStateCopyWith<$Res> { + __$$_HomeTabStateCopyWithImpl( + _$_HomeTabState _value, $Res Function(_$_HomeTabState) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? tabs = null, + Object? currentIndex = null, + }) { + return _then(_$_HomeTabState( + tabs: null == tabs + ? _value._tabs + : tabs // ignore: cast_nullable_to_non_nullable + as List, + currentIndex: null == currentIndex + ? _value.currentIndex + : currentIndex // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$_HomeTabState implements _HomeTabState { + const _$_HomeTabState( + {required final List tabs, required this.currentIndex}) + : _tabs = tabs; + + final List _tabs; + @override + List get tabs { + if (_tabs is EqualUnmodifiableListView) return _tabs; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_tabs); + } + + @override + final int currentIndex; + + @override + String toString() { + return 'HomeTabState(tabs: $tabs, currentIndex: $currentIndex)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_HomeTabState && + const DeepCollectionEquality().equals(other._tabs, _tabs) && + (identical(other.currentIndex, currentIndex) || + other.currentIndex == currentIndex)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_tabs), currentIndex); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_HomeTabStateCopyWith<_$_HomeTabState> get copyWith => + __$$_HomeTabStateCopyWithImpl<_$_HomeTabState>(this, _$identity); +} + +abstract class _HomeTabState implements HomeTabState { + const factory _HomeTabState( + {required final List tabs, + required final int currentIndex}) = _$_HomeTabState; + + @override + List get tabs; + @override + int get currentIndex; + @override + @JsonKey(ignore: true) + _$$_HomeTabStateCopyWith<_$_HomeTabState> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/bloc/home_tab_event.dart b/lib/bloc/home_tab_event.dart new file mode 100644 index 0000000..93bbb76 --- /dev/null +++ b/lib/bloc/home_tab_event.dart @@ -0,0 +1,12 @@ +part of 'home_tab_bloc.dart'; + +@freezed +class HomeTabEvent with _$HomeTabEvent { + const factory HomeTabEvent.add(TabItem tab) = _Add; + + const factory HomeTabEvent.remove(TabItem tab) = _Remove; + + const factory HomeTabEvent.change(int index) = _Change; + + const factory HomeTabEvent.reorder(int oldIndex, int newIndex) = _Reorder; +} diff --git a/lib/bloc/home_tab_state.dart b/lib/bloc/home_tab_state.dart new file mode 100644 index 0000000..53e8d3b --- /dev/null +++ b/lib/bloc/home_tab_state.dart @@ -0,0 +1,20 @@ +part of 'home_tab_bloc.dart'; + +const freezed = Freezed( + equal: true, + copyWith: true, + toStringOverride: true, + makeCollectionsUnmodifiable: true); + +@freezed +class HomeTabState with _$HomeTabState { + const factory HomeTabState({ + required List tabs, + required int currentIndex, + }) = _HomeTabState; + + factory HomeTabState.initial({TabItem? init}) => HomeTabState( + tabs: init == null ? [] : [init], + currentIndex: -1, + ); +} diff --git a/lib/bloc/profiles_search_cubit.dart b/lib/bloc/profiles_search_cubit.dart new file mode 100644 index 0000000..139f288 --- /dev/null +++ b/lib/bloc/profiles_search_cubit.dart @@ -0,0 +1,101 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:fterm/di/di.dart'; +import 'package:fterm/gen/assets.gen.dart'; +import 'package:hive/hive.dart'; +import 'package:injectable/injectable.dart'; +import '../model/shell.dart'; +import '../model/ssh_config.dart'; + +part 'profiles_search_state.dart'; + +part 'profiles_search_cubit.freezed.dart'; + +@singleton +class ProfilesSearchCubit extends Cubit { + ProfilesSearchCubit() + : super(const ProfilesState.initial( + [Item.hosts("主机", true, []), Item.shells("本地", true, [])], "")) { + load(); + } + + @override + Future close() { + print("ProfilesSearchCubit.close"); + return super.close(); + } + + void expanded(int index, bool isExpanded) { + var items = List.of(state.items); + items[index] = items[index].copyWith(isExpanded: isExpanded); + emit(state.copyWith(items: items)); + } + + Future load() async { + var box = getIt>(); + var hosts = box.values.toList(); + var shells = await _shells(); + emit(state.copyWith( + items: [ + ...state.items.map((e) { + return e.map(hosts: (item) { + return item.copyWith(hosts: hosts); + }, shells: (item) { + return item.copyWith(shells: shells); + }); + }) + ], + )); + } + + Future> _shells() async { + if (Platform.isMacOS || Platform.isLinux) { + var shells = await File("/etc/shells").readAsLines(); + shells = shells + .skipWhile((value) => value.startsWith("#") || value.trim().isEmpty) + .toList(); + return shells.map((e) => Shell(e, e)).toList(); + } else if (Platform.isWindows) { + return [ + Shell( + "cmd", + "cmd.exe", + icon: Assets.icons.cmd.svg(width: 16, height: 16), + ), + Shell( + "Powershell", + "powershell.exe", + icon: Assets.icons.powershell.svg(width: 16, height: 16), + ) + ]; + if (Process.runSync("where", ["wsl.exe"]).exitCode == 0) { + ProcessResult result = await Process.run("wsl", ['-l', '-q']); + List distros = const LineSplitter() + .convert(result.stdout) + .map((e) => String.fromCharCodes( + e.codeUnits.where((element) => element > 0))) + .where((element) => element.isNotEmpty) + .toList(); + // return distros.map((e) => Shell(e,"cmd", ["/k","wsl","-d",e])).toList(); + return distros.map( + (e) { + var envs2 = { + "TERM": 'xterm-color', + "COLORTERM": 'truecolor', + }; + var args2 = ["-d", e]; + return Shell(e, "wsl", args: args2, envs: envs2); + }, + ).toList(); + } + } + return []; + } + + void search(String keyword) { + emit(state.copyWith(keyword: keyword)); + } +} diff --git a/lib/bloc/profiles_search_cubit.freezed.dart b/lib/bloc/profiles_search_cubit.freezed.dart new file mode 100644 index 0000000..65ecc28 --- /dev/null +++ b/lib/bloc/profiles_search_cubit.freezed.dart @@ -0,0 +1,673 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'profiles_search_cubit.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$ProfilesState { + List get items => throw _privateConstructorUsedError; + String get keyword => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function(List items, String keyword) initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(List items, String keyword)? initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(List items, String keyword)? initial, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ProfilesStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProfilesStateCopyWith<$Res> { + factory $ProfilesStateCopyWith( + ProfilesState value, $Res Function(ProfilesState) then) = + _$ProfilesStateCopyWithImpl<$Res, ProfilesState>; + @useResult + $Res call({List items, String keyword}); +} + +/// @nodoc +class _$ProfilesStateCopyWithImpl<$Res, $Val extends ProfilesState> + implements $ProfilesStateCopyWith<$Res> { + _$ProfilesStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? items = null, + Object? keyword = null, + }) { + return _then(_value.copyWith( + items: null == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as List, + keyword: null == keyword + ? _value.keyword + : keyword // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_InitialCopyWith<$Res> + implements $ProfilesStateCopyWith<$Res> { + factory _$$_InitialCopyWith( + _$_Initial value, $Res Function(_$_Initial) then) = + __$$_InitialCopyWithImpl<$Res>; + @override + @useResult + $Res call({List items, String keyword}); +} + +/// @nodoc +class __$$_InitialCopyWithImpl<$Res> + extends _$ProfilesStateCopyWithImpl<$Res, _$_Initial> + implements _$$_InitialCopyWith<$Res> { + __$$_InitialCopyWithImpl(_$_Initial _value, $Res Function(_$_Initial) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? items = null, + Object? keyword = null, + }) { + return _then(_$_Initial( + null == items + ? _value._items + : items // ignore: cast_nullable_to_non_nullable + as List, + null == keyword + ? _value.keyword + : keyword // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_Initial implements _Initial { + const _$_Initial(final List items, this.keyword) : _items = items; + + final List _items; + @override + List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); + } + + @override + final String keyword; + + @override + String toString() { + return 'ProfilesState.initial(items: $items, keyword: $keyword)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Initial && + const DeepCollectionEquality().equals(other._items, _items) && + (identical(other.keyword, keyword) || other.keyword == keyword)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_items), keyword); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_InitialCopyWith<_$_Initial> get copyWith => + __$$_InitialCopyWithImpl<_$_Initial>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(List items, String keyword) initial, + }) { + return initial(items, keyword); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(List items, String keyword)? initial, + }) { + return initial?.call(items, keyword); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(List items, String keyword)? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(items, keyword); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _Initial implements ProfilesState { + const factory _Initial(final List items, final String keyword) = + _$_Initial; + + @override + List get items; + @override + String get keyword; + @override + @JsonKey(ignore: true) + _$$_InitialCopyWith<_$_Initial> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$Item { + String get header => throw _privateConstructorUsedError; + bool get isExpanded => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function( + String header, bool isExpanded, List hosts) + hosts, + required TResult Function( + String header, bool isExpanded, List shells) + shells, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String header, bool isExpanded, List hosts)? + hosts, + TResult? Function(String header, bool isExpanded, List shells)? + shells, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String header, bool isExpanded, List hosts)? + hosts, + TResult Function(String header, bool isExpanded, List shells)? + shells, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Hosts value) hosts, + required TResult Function(_Shells value) shells, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Hosts value)? hosts, + TResult? Function(_Shells value)? shells, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Hosts value)? hosts, + TResult Function(_Shells value)? shells, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ItemCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ItemCopyWith<$Res> { + factory $ItemCopyWith(Item value, $Res Function(Item) then) = + _$ItemCopyWithImpl<$Res, Item>; + @useResult + $Res call({String header, bool isExpanded}); +} + +/// @nodoc +class _$ItemCopyWithImpl<$Res, $Val extends Item> + implements $ItemCopyWith<$Res> { + _$ItemCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? header = null, + Object? isExpanded = null, + }) { + return _then(_value.copyWith( + header: null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable + as String, + isExpanded: null == isExpanded + ? _value.isExpanded + : isExpanded // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_HostsCopyWith<$Res> implements $ItemCopyWith<$Res> { + factory _$$_HostsCopyWith(_$_Hosts value, $Res Function(_$_Hosts) then) = + __$$_HostsCopyWithImpl<$Res>; + @override + @useResult + $Res call({String header, bool isExpanded, List hosts}); +} + +/// @nodoc +class __$$_HostsCopyWithImpl<$Res> extends _$ItemCopyWithImpl<$Res, _$_Hosts> + implements _$$_HostsCopyWith<$Res> { + __$$_HostsCopyWithImpl(_$_Hosts _value, $Res Function(_$_Hosts) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? header = null, + Object? isExpanded = null, + Object? hosts = null, + }) { + return _then(_$_Hosts( + null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable + as String, + null == isExpanded + ? _value.isExpanded + : isExpanded // ignore: cast_nullable_to_non_nullable + as bool, + null == hosts + ? _value._hosts + : hosts // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_Hosts implements _Hosts { + const _$_Hosts(this.header, this.isExpanded, final List hosts) + : _hosts = hosts; + + @override + final String header; + @override + final bool isExpanded; + final List _hosts; + @override + List get hosts { + if (_hosts is EqualUnmodifiableListView) return _hosts; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_hosts); + } + + @override + String toString() { + return 'Item.hosts(header: $header, isExpanded: $isExpanded, hosts: $hosts)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Hosts && + (identical(other.header, header) || other.header == header) && + (identical(other.isExpanded, isExpanded) || + other.isExpanded == isExpanded) && + const DeepCollectionEquality().equals(other._hosts, _hosts)); + } + + @override + int get hashCode => Object.hash(runtimeType, header, isExpanded, + const DeepCollectionEquality().hash(_hosts)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_HostsCopyWith<_$_Hosts> get copyWith => + __$$_HostsCopyWithImpl<_$_Hosts>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + String header, bool isExpanded, List hosts) + hosts, + required TResult Function( + String header, bool isExpanded, List shells) + shells, + }) { + return hosts(header, isExpanded, this.hosts); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String header, bool isExpanded, List hosts)? + hosts, + TResult? Function(String header, bool isExpanded, List shells)? + shells, + }) { + return hosts?.call(header, isExpanded, this.hosts); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String header, bool isExpanded, List hosts)? + hosts, + TResult Function(String header, bool isExpanded, List shells)? + shells, + required TResult orElse(), + }) { + if (hosts != null) { + return hosts(header, isExpanded, this.hosts); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Hosts value) hosts, + required TResult Function(_Shells value) shells, + }) { + return hosts(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Hosts value)? hosts, + TResult? Function(_Shells value)? shells, + }) { + return hosts?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Hosts value)? hosts, + TResult Function(_Shells value)? shells, + required TResult orElse(), + }) { + if (hosts != null) { + return hosts(this); + } + return orElse(); + } +} + +abstract class _Hosts implements Item { + const factory _Hosts(final String header, final bool isExpanded, + final List hosts) = _$_Hosts; + + @override + String get header; + @override + bool get isExpanded; + List get hosts; + @override + @JsonKey(ignore: true) + _$$_HostsCopyWith<_$_Hosts> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_ShellsCopyWith<$Res> implements $ItemCopyWith<$Res> { + factory _$$_ShellsCopyWith(_$_Shells value, $Res Function(_$_Shells) then) = + __$$_ShellsCopyWithImpl<$Res>; + @override + @useResult + $Res call({String header, bool isExpanded, List shells}); +} + +/// @nodoc +class __$$_ShellsCopyWithImpl<$Res> extends _$ItemCopyWithImpl<$Res, _$_Shells> + implements _$$_ShellsCopyWith<$Res> { + __$$_ShellsCopyWithImpl(_$_Shells _value, $Res Function(_$_Shells) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? header = null, + Object? isExpanded = null, + Object? shells = null, + }) { + return _then(_$_Shells( + null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable + as String, + null == isExpanded + ? _value.isExpanded + : isExpanded // ignore: cast_nullable_to_non_nullable + as bool, + null == shells + ? _value._shells + : shells // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_Shells implements _Shells { + const _$_Shells(this.header, this.isExpanded, final List shells) + : _shells = shells; + + @override + final String header; + @override + final bool isExpanded; + final List _shells; + @override + List get shells { + if (_shells is EqualUnmodifiableListView) return _shells; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_shells); + } + + @override + String toString() { + return 'Item.shells(header: $header, isExpanded: $isExpanded, shells: $shells)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Shells && + (identical(other.header, header) || other.header == header) && + (identical(other.isExpanded, isExpanded) || + other.isExpanded == isExpanded) && + const DeepCollectionEquality().equals(other._shells, _shells)); + } + + @override + int get hashCode => Object.hash(runtimeType, header, isExpanded, + const DeepCollectionEquality().hash(_shells)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_ShellsCopyWith<_$_Shells> get copyWith => + __$$_ShellsCopyWithImpl<_$_Shells>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + String header, bool isExpanded, List hosts) + hosts, + required TResult Function( + String header, bool isExpanded, List shells) + shells, + }) { + return shells(header, isExpanded, this.shells); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String header, bool isExpanded, List hosts)? + hosts, + TResult? Function(String header, bool isExpanded, List shells)? + shells, + }) { + return shells?.call(header, isExpanded, this.shells); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String header, bool isExpanded, List hosts)? + hosts, + TResult Function(String header, bool isExpanded, List shells)? + shells, + required TResult orElse(), + }) { + if (shells != null) { + return shells(header, isExpanded, this.shells); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Hosts value) hosts, + required TResult Function(_Shells value) shells, + }) { + return shells(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Hosts value)? hosts, + TResult? Function(_Shells value)? shells, + }) { + return shells?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Hosts value)? hosts, + TResult Function(_Shells value)? shells, + required TResult orElse(), + }) { + if (shells != null) { + return shells(this); + } + return orElse(); + } +} + +abstract class _Shells implements Item { + const factory _Shells(final String header, final bool isExpanded, + final List shells) = _$_Shells; + + @override + String get header; + @override + bool get isExpanded; + List get shells; + @override + @JsonKey(ignore: true) + _$$_ShellsCopyWith<_$_Shells> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/bloc/profiles_search_state.dart b/lib/bloc/profiles_search_state.dart new file mode 100644 index 0000000..f5342c4 --- /dev/null +++ b/lib/bloc/profiles_search_state.dart @@ -0,0 +1,26 @@ +part of 'profiles_search_cubit.dart'; + +const freezed = Freezed(copyWith: true, equal: true); + +@freezed +class ProfilesState with _$ProfilesState { + const factory ProfilesState.initial( + List items, + String keyword, + ) = _Initial; +} + +@freezed +class Item with _$Item { + const factory Item.hosts( + String header, + bool isExpanded, + List hosts, + ) = _Hosts; + + const factory Item.shells( + String header, + bool isExpanded, + List shells, + ) = _Shells; +} diff --git a/lib/bloc/ssh_config_bloc.dart b/lib/bloc/ssh_config_bloc.dart new file mode 100644 index 0000000..3681a0a --- /dev/null +++ b/lib/bloc/ssh_config_bloc.dart @@ -0,0 +1,31 @@ +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:fterm/model/ssh_config.dart'; +import 'package:hive/hive.dart'; +import 'package:injectable/injectable.dart'; + +import '../di/di.dart'; + +part 'ssh_config_event.dart'; + +part 'ssh_config_state.dart'; + +part 'ssh_config_bloc.freezed.dart'; + +@singleton +class SshConfigBloc extends Bloc { + SshConfigBloc() : super(const SshConfigState.initial([])) { + on((event, emit) async { + await event.map(load: (e) async { + var box = getIt>(); + var items = box.values.toList(); + emit(state.copyWith(configs: items)); + }, add: (e) async { + var box = getIt>(); + box.put(e.config.id, e.config); + add(const SshConfigEvent.load()); + }); + }); + add(const SshConfigEvent.load()); + } +} diff --git a/lib/bloc/ssh_config_bloc.freezed.dart b/lib/bloc/ssh_config_bloc.freezed.dart new file mode 100644 index 0000000..106ef72 --- /dev/null +++ b/lib/bloc/ssh_config_bloc.freezed.dart @@ -0,0 +1,515 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'ssh_config_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$SshConfigEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() load, + required TResult Function(SSHConfig config) add, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? load, + TResult? Function(SSHConfig config)? add, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? load, + TResult Function(SSHConfig config)? add, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Load value) load, + required TResult Function(_Add value) add, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Load value)? load, + TResult? Function(_Add value)? add, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Load value)? load, + TResult Function(_Add value)? add, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SshConfigEventCopyWith<$Res> { + factory $SshConfigEventCopyWith( + SshConfigEvent value, $Res Function(SshConfigEvent) then) = + _$SshConfigEventCopyWithImpl<$Res, SshConfigEvent>; +} + +/// @nodoc +class _$SshConfigEventCopyWithImpl<$Res, $Val extends SshConfigEvent> + implements $SshConfigEventCopyWith<$Res> { + _$SshConfigEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_LoadCopyWith<$Res> { + factory _$$_LoadCopyWith(_$_Load value, $Res Function(_$_Load) then) = + __$$_LoadCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LoadCopyWithImpl<$Res> + extends _$SshConfigEventCopyWithImpl<$Res, _$_Load> + implements _$$_LoadCopyWith<$Res> { + __$$_LoadCopyWithImpl(_$_Load _value, $Res Function(_$_Load) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Load implements _Load { + const _$_Load(); + + @override + String toString() { + return 'SshConfigEvent.load()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Load); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() load, + required TResult Function(SSHConfig config) add, + }) { + return load(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? load, + TResult? Function(SSHConfig config)? add, + }) { + return load?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? load, + TResult Function(SSHConfig config)? add, + required TResult orElse(), + }) { + if (load != null) { + return load(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Load value) load, + required TResult Function(_Add value) add, + }) { + return load(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Load value)? load, + TResult? Function(_Add value)? add, + }) { + return load?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Load value)? load, + TResult Function(_Add value)? add, + required TResult orElse(), + }) { + if (load != null) { + return load(this); + } + return orElse(); + } +} + +abstract class _Load implements SshConfigEvent { + const factory _Load() = _$_Load; +} + +/// @nodoc +abstract class _$$_AddCopyWith<$Res> { + factory _$$_AddCopyWith(_$_Add value, $Res Function(_$_Add) then) = + __$$_AddCopyWithImpl<$Res>; + @useResult + $Res call({SSHConfig config}); +} + +/// @nodoc +class __$$_AddCopyWithImpl<$Res> + extends _$SshConfigEventCopyWithImpl<$Res, _$_Add> + implements _$$_AddCopyWith<$Res> { + __$$_AddCopyWithImpl(_$_Add _value, $Res Function(_$_Add) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? config = null, + }) { + return _then(_$_Add( + null == config + ? _value.config + : config // ignore: cast_nullable_to_non_nullable + as SSHConfig, + )); + } +} + +/// @nodoc + +class _$_Add implements _Add { + const _$_Add(this.config); + + @override + final SSHConfig config; + + @override + String toString() { + return 'SshConfigEvent.add(config: $config)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Add && + (identical(other.config, config) || other.config == config)); + } + + @override + int get hashCode => Object.hash(runtimeType, config); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AddCopyWith<_$_Add> get copyWith => + __$$_AddCopyWithImpl<_$_Add>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() load, + required TResult Function(SSHConfig config) add, + }) { + return add(config); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? load, + TResult? Function(SSHConfig config)? add, + }) { + return add?.call(config); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? load, + TResult Function(SSHConfig config)? add, + required TResult orElse(), + }) { + if (add != null) { + return add(config); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Load value) load, + required TResult Function(_Add value) add, + }) { + return add(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Load value)? load, + TResult? Function(_Add value)? add, + }) { + return add?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Load value)? load, + TResult Function(_Add value)? add, + required TResult orElse(), + }) { + if (add != null) { + return add(this); + } + return orElse(); + } +} + +abstract class _Add implements SshConfigEvent { + const factory _Add(final SSHConfig config) = _$_Add; + + SSHConfig get config; + @JsonKey(ignore: true) + _$$_AddCopyWith<_$_Add> get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$SshConfigState { + List get configs => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function(List configs) initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(List configs)? initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(List configs)? initial, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SshConfigStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SshConfigStateCopyWith<$Res> { + factory $SshConfigStateCopyWith( + SshConfigState value, $Res Function(SshConfigState) then) = + _$SshConfigStateCopyWithImpl<$Res, SshConfigState>; + @useResult + $Res call({List configs}); +} + +/// @nodoc +class _$SshConfigStateCopyWithImpl<$Res, $Val extends SshConfigState> + implements $SshConfigStateCopyWith<$Res> { + _$SshConfigStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? configs = null, + }) { + return _then(_value.copyWith( + configs: null == configs + ? _value.configs + : configs // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_InitialCopyWith<$Res> + implements $SshConfigStateCopyWith<$Res> { + factory _$$_InitialCopyWith( + _$_Initial value, $Res Function(_$_Initial) then) = + __$$_InitialCopyWithImpl<$Res>; + @override + @useResult + $Res call({List configs}); +} + +/// @nodoc +class __$$_InitialCopyWithImpl<$Res> + extends _$SshConfigStateCopyWithImpl<$Res, _$_Initial> + implements _$$_InitialCopyWith<$Res> { + __$$_InitialCopyWithImpl(_$_Initial _value, $Res Function(_$_Initial) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? configs = null, + }) { + return _then(_$_Initial( + null == configs + ? _value._configs + : configs // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_Initial implements _Initial { + const _$_Initial(final List configs) : _configs = configs; + + final List _configs; + @override + List get configs { + if (_configs is EqualUnmodifiableListView) return _configs; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_configs); + } + + @override + String toString() { + return 'SshConfigState.initial(configs: $configs)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Initial && + const DeepCollectionEquality().equals(other._configs, _configs)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_configs)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_InitialCopyWith<_$_Initial> get copyWith => + __$$_InitialCopyWithImpl<_$_Initial>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(List configs) initial, + }) { + return initial(configs); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(List configs)? initial, + }) { + return initial?.call(configs); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(List configs)? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(configs); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _Initial implements SshConfigState { + const factory _Initial(final List configs) = _$_Initial; + + @override + List get configs; + @override + @JsonKey(ignore: true) + _$$_InitialCopyWith<_$_Initial> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/bloc/ssh_config_event.dart b/lib/bloc/ssh_config_event.dart new file mode 100644 index 0000000..61e1eb5 --- /dev/null +++ b/lib/bloc/ssh_config_event.dart @@ -0,0 +1,8 @@ +part of 'ssh_config_bloc.dart'; + +@freezed +class SshConfigEvent with _$SshConfigEvent { + const factory SshConfigEvent.load() = _Load; + + const factory SshConfigEvent.add(SSHConfig config) = _Add; +} diff --git a/lib/bloc/ssh_config_state.dart b/lib/bloc/ssh_config_state.dart new file mode 100644 index 0000000..083a84c --- /dev/null +++ b/lib/bloc/ssh_config_state.dart @@ -0,0 +1,6 @@ +part of 'ssh_config_bloc.dart'; + +@freezed +class SshConfigState with _$SshConfigState { + const factory SshConfigState.initial(List configs) = _Initial; +} diff --git a/lib/bootstrap/launcher.dart b/lib/bootstrap/launcher.dart new file mode 100644 index 0000000..7e5fac4 --- /dev/null +++ b/lib/bootstrap/launcher.dart @@ -0,0 +1,53 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/bloc/profiles_search_cubit.dart'; +import 'package:fterm/di/di.dart'; +import 'package:statsfl/statsfl.dart'; + +import '../bloc/home_tab_bloc.dart'; +import '../bloc/ssh_config_bloc.dart'; +import '../ui/term_app.dart'; +import 'options.dart'; +import 'runner.dart'; + +class Launcher implements EntryPoint { + @override + Widget create(LaunchOptions options) { + var app = const TermApp(); + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => getIt(), + ), + BlocProvider( + create: (context) => getIt(), + ), + BlocProvider( + create: (context) => getIt(), + ), + BlocProvider( + create: (context) => getIt(), + ), + ], + child: Builder(builder: (context) { + return BlocListener( + listener: (context, state) { + getIt().load(); + }, + child: BlocBuilder( + builder: (context, state) { + return StatsFl( + align: Alignment.topCenter, + maxFps: 60, + isEnabled: kDebugMode && state.showFPS, + child: app, + ); + }, + ), + ); + }), + ); + } +} diff --git a/lib/bootstrap/options.dart b/lib/bootstrap/options.dart new file mode 100644 index 0000000..1f35767 --- /dev/null +++ b/lib/bootstrap/options.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:fterm/model/tab_item.dart'; + +part 'options.freezed.dart'; + +const Freezed freezed = Freezed( + toStringOverride: true, + equal: true, +); + +@freezed +class LaunchOptions with _$LaunchOptions { + const factory LaunchOptions( + {Locale? locale, TabItem? initTab, String? token}) = _LaunchOptions; +} diff --git a/lib/bootstrap/options.freezed.dart b/lib/bootstrap/options.freezed.dart new file mode 100644 index 0000000..fedd001 --- /dev/null +++ b/lib/bootstrap/options.freezed.dart @@ -0,0 +1,167 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'options.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$LaunchOptions { + Locale? get locale => throw _privateConstructorUsedError; + TabItem? get initTab => throw _privateConstructorUsedError; + String? get token => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $LaunchOptionsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LaunchOptionsCopyWith<$Res> { + factory $LaunchOptionsCopyWith( + LaunchOptions value, $Res Function(LaunchOptions) then) = + _$LaunchOptionsCopyWithImpl<$Res, LaunchOptions>; + @useResult + $Res call({Locale? locale, TabItem? initTab, String? token}); +} + +/// @nodoc +class _$LaunchOptionsCopyWithImpl<$Res, $Val extends LaunchOptions> + implements $LaunchOptionsCopyWith<$Res> { + _$LaunchOptionsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? initTab = freezed, + Object? token = freezed, + }) { + return _then(_value.copyWith( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale?, + initTab: freezed == initTab + ? _value.initTab + : initTab // ignore: cast_nullable_to_non_nullable + as TabItem?, + token: freezed == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_LaunchOptionsCopyWith<$Res> + implements $LaunchOptionsCopyWith<$Res> { + factory _$$_LaunchOptionsCopyWith( + _$_LaunchOptions value, $Res Function(_$_LaunchOptions) then) = + __$$_LaunchOptionsCopyWithImpl<$Res>; + @override + @useResult + $Res call({Locale? locale, TabItem? initTab, String? token}); +} + +/// @nodoc +class __$$_LaunchOptionsCopyWithImpl<$Res> + extends _$LaunchOptionsCopyWithImpl<$Res, _$_LaunchOptions> + implements _$$_LaunchOptionsCopyWith<$Res> { + __$$_LaunchOptionsCopyWithImpl( + _$_LaunchOptions _value, $Res Function(_$_LaunchOptions) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? initTab = freezed, + Object? token = freezed, + }) { + return _then(_$_LaunchOptions( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale?, + initTab: freezed == initTab + ? _value.initTab + : initTab // ignore: cast_nullable_to_non_nullable + as TabItem?, + token: freezed == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$_LaunchOptions implements _LaunchOptions { + const _$_LaunchOptions({this.locale, this.initTab, this.token}); + + @override + final Locale? locale; + @override + final TabItem? initTab; + @override + final String? token; + + @override + String toString() { + return 'LaunchOptions(locale: $locale, initTab: $initTab, token: $token)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_LaunchOptions && + (identical(other.locale, locale) || other.locale == locale) && + (identical(other.initTab, initTab) || other.initTab == initTab) && + (identical(other.token, token) || other.token == token)); + } + + @override + int get hashCode => Object.hash(runtimeType, locale, initTab, token); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_LaunchOptionsCopyWith<_$_LaunchOptions> get copyWith => + __$$_LaunchOptionsCopyWithImpl<_$_LaunchOptions>(this, _$identity); +} + +abstract class _LaunchOptions implements LaunchOptions { + const factory _LaunchOptions( + {final Locale? locale, + final TabItem? initTab, + final String? token}) = _$_LaunchOptions; + + @override + Locale? get locale; + @override + TabItem? get initTab; + @override + String? get token; + @override + @JsonKey(ignore: true) + _$$_LaunchOptionsCopyWith<_$_LaunchOptions> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/bootstrap/runner.dart b/lib/bootstrap/runner.dart new file mode 100644 index 0000000..acb18e6 --- /dev/null +++ b/lib/bootstrap/runner.dart @@ -0,0 +1,90 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:fterm/bloc/home_tab_bloc.dart'; +import 'package:fterm/bootstrap/tasks/windows_task.dart'; +import 'package:get_it/get_it.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:injectable/injectable.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import '../bloc/app_config_cubit.dart'; +import '../di/di.dart'; +import '../model/ssh_config.dart'; +import 'options.dart'; +import 'tasks/app_widget_task.dart'; +import 'tasks/init_data_task.dart'; +import 'package:path/path.dart' if (dart.library.html) 'src/stub/path.dart' + as path_helper; + +enum LaunchTaskType { Async, Sync } + +class LaunchContext { + GetIt getIt; + LaunchOptions options; + + LaunchContext(this.getIt, this.options); +} + +abstract class LaunchTask { + LaunchTaskType get type => LaunchTaskType.Async; + + Future initialize(LaunchContext context); +} + +@singleton +class AppLauncher { + List tasks; + + AppLauncher() : tasks = List.from([]); + + void addTask(LaunchTask task) { + tasks.add(task); + } + + Future launch(LaunchOptions options) async { + final LaunchContext context = LaunchContext(getIt, options); + for (LaunchTask task in tasks) { + if (task.type == LaunchTaskType.Async) { + task.initialize(context); + } else { + await task.initialize(context); + } + } + } +} + +abstract class EntryPoint { + Widget create(LaunchOptions options); +} + +typedef Options = Future Function(); + +class AppRunner { + static _ensureInitialized() async { + WidgetsFlutterBinding.ensureInitialized(); + await Hive.initFlutter(); + var appDir = await getApplicationDocumentsDirectory(); + String subDir = "fterm"; + var path = path_helper.join(appDir.path, subDir); + Hive.init(path); + Hive.registerAdapter(SSHConfigAdapter()); + Hive.registerAdapter(AuthTypeAdapter()); + } + + static Future run(EntryPoint root, Options options) async { + await _ensureInitialized(); + await configureDependencies(); + var launchOptions = await options(); + getIt.registerSingleton(root); + getIt.registerSingleton(AppConfigCubit(startLocal: launchOptions.locale)); + getIt.registerSingleton(HomeTabBloc(init: launchOptions.initTab)); + + var appLauncher = getIt(); + + appLauncher.addTask(InitDataTask()); + appLauncher.addTask(WindowsTask()); + appLauncher.addTask(InitAppWidgetTask()); + appLauncher.launch(launchOptions); + } +} diff --git a/lib/bootstrap/tasks/app_widget_task.dart b/lib/bootstrap/tasks/app_widget_task.dart new file mode 100644 index 0000000..0142f0b --- /dev/null +++ b/lib/bootstrap/tasks/app_widget_task.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +import '../runner.dart'; + +class InitAppWidgetTask extends LaunchTask { + @override + LaunchTaskType get type => LaunchTaskType.Sync; + + @override + Future initialize(LaunchContext context) async { + debugPrint("InitAppWidgetTask"); + Widget app = context.getIt().create(context.options); + runApp(app); + return Future(() => {}); + } +} diff --git a/lib/bootstrap/tasks/init_data_task.dart b/lib/bootstrap/tasks/init_data_task.dart new file mode 100644 index 0000000..6c037e0 --- /dev/null +++ b/lib/bootstrap/tasks/init_data_task.dart @@ -0,0 +1,37 @@ +import 'package:flutter/foundation.dart'; +import 'package:fterm/service/sync_service.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../bloc/app_config_cubit.dart'; +import '../../bloc/home_tab_bloc.dart'; +import '../../di/di.dart'; +import '../../ui/connector/local_connector.dart'; +import '../../ui/terminal_panel.dart'; +import '../runner.dart'; +import '../../utils/string_ext.dart'; + +class InitDataTask extends LaunchTask { + @override + LaunchTaskType get type => LaunchTaskType.Async; + + @override + Future initialize(LaunchContext context) async { + debugPrint("InitDataTask"); + getIt().init(); + var connector = LocalConnector(); + getIt().add(HomeTabEvent.add( + TerminalTab(connector.executable, connector, icon: connector.icon), + )); + var locale = await SharedPreferences.getInstance() + .then((value) => value.getString("lang")?.toLocale()); + if (locale == null) { + getIt().clearLocal(); + } else { + getIt().setLocal(locale); + } + var syncService = getIt(); + syncService.pull().then( + (value) => syncService.push(), + ); + } +} diff --git a/lib/bootstrap/tasks/windows_task.dart b/lib/bootstrap/tasks/windows_task.dart new file mode 100644 index 0000000..18dd9de --- /dev/null +++ b/lib/bootstrap/tasks/windows_task.dart @@ -0,0 +1,21 @@ +import 'package:fluent_ui/fluent_ui.dart'; + +import '../runner.dart'; +import 'package:bitsdojo_window/bitsdojo_window.dart'; + +class WindowsTask extends LaunchTask { + @override + LaunchTaskType get type => LaunchTaskType.Sync; + + @override + Future initialize(LaunchContext context) async { + debugPrint("WindowsTask"); + doWhenWindowReady(() { + const initialSize = Size(900, 600); + appWindow.minSize = const Size(600, 400); + appWindow.size = initialSize; + appWindow.alignment = Alignment.center; + appWindow.show(); + }); + } +} diff --git a/lib/di/di.config.dart b/lib/di/di.config.dart new file mode 100644 index 0000000..8425512 --- /dev/null +++ b/lib/di/di.config.dart @@ -0,0 +1,52 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// InjectableConfigGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_lambdas +// ignore_for_file: lines_longer_than_80_chars +// coverage:ignore-file + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:flutter_secure_storage/flutter_secure_storage.dart' as _i6; +import 'package:get_it/get_it.dart' as _i1; +import 'package:hive_flutter/hive_flutter.dart' as _i4; +import 'package:injectable/injectable.dart' as _i2; + +import '../bloc/profiles_search_cubit.dart' as _i7; +import '../bloc/ssh_config_bloc.dart' as _i8; +import '../bootstrap/runner.dart' as _i3; +import '../model/ssh_config.dart' as _i5; +import '../service/sync_service.dart' as _i9; +import '../service/webdav_sync_service.dart' as _i10; +import 'register_modules.dart' as _i11; + +extension GetItInjectableX on _i1.GetIt { + // initializes the registration of main-scope dependencies inside of GetIt + Future<_i1.GetIt> init({ + String? environment, + _i2.EnvironmentFilter? environmentFilter, + }) async { + final gh = _i2.GetItHelper( + this, + environment, + environmentFilter, + ); + final registerModule = _$RegisterModule(); + gh.singleton<_i3.AppLauncher>(_i3.AppLauncher()); + await gh.singletonAsync<_i4.Box<_i5.SSHConfig>>( + () => registerModule.providerBox, + preResolve: true, + ); + gh.singleton<_i6.FlutterSecureStorage>( + registerModule.provideFlutterSecureStorage); + gh.singleton<_i7.ProfilesSearchCubit>(_i7.ProfilesSearchCubit()); + gh.singleton<_i8.SshConfigBloc>(_i8.SshConfigBloc()); + gh.singleton<_i9.SyncService>( + _i10.WebDAVSyncService(gh<_i6.FlutterSecureStorage>())..init()); + return this; + } +} + +class _$RegisterModule extends _i11.RegisterModule {} diff --git a/lib/di/di.dart b/lib/di/di.dart new file mode 100644 index 0000000..0c0dd33 --- /dev/null +++ b/lib/di/di.dart @@ -0,0 +1,11 @@ +import 'package:get_it/get_it.dart'; +import 'package:injectable/injectable.dart'; +import 'di.config.dart'; +final getIt = GetIt.instance; + +@InjectableInit( + initializerName: 'init', // default + preferRelativeImports: true, // default + asExtension: true, // default +) +configureDependencies() => getIt.init(); diff --git a/lib/di/register_modules.dart b/lib/di/register_modules.dart new file mode 100644 index 0000000..1b52781 --- /dev/null +++ b/lib/di/register_modules.dart @@ -0,0 +1,42 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:injectable/injectable.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../model/ssh_config.dart'; + +@module +abstract class RegisterModule { + @singleton + FlutterSecureStorage get provideFlutterSecureStorage { + const secureStorage = FlutterSecureStorage(); + return secureStorage; + } + + @singleton + @preResolve + Future> get providerBox async { + const secureStorage = FlutterSecureStorage(); + // if key not exists return null + final encryptionKeyString = await secureStorage.read(key: 'hive'); + if (encryptionKeyString == null) { + final key = Hive.generateSecureKey(); + await secureStorage.write( + key: 'hive', + value: base64UrlEncode(key), + ); + } + final key = await secureStorage.read(key: 'hive'); + final encryptionKeyUint8List = base64Url.decode(key!); + print('Encryption key Uint8List: $encryptionKeyUint8List'); + + var box = await Hive.openBox('ssh', + encryptionCipher: HiveAesCipher(encryptionKeyUint8List)); + // await box.clear(); + return box; + } +} diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart new file mode 100644 index 0000000..a5dd160 --- /dev/null +++ b/lib/gen/assets.gen.dart @@ -0,0 +1,275 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +import 'package:flutter/widgets.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter/services.dart'; + +class $AssetsIconsGen { + const $AssetsIconsGen(); + + /// File path: assets/icons/alma.svg + SvgGenImage get alma => const SvgGenImage('assets/icons/alma.svg'); + + /// File path: assets/icons/alpine.svg + SvgGenImage get alpine => const SvgGenImage('assets/icons/alpine.svg'); + + /// File path: assets/icons/clink.svg + SvgGenImage get clink => const SvgGenImage('assets/icons/clink.svg'); + + /// File path: assets/icons/cmd.svg + SvgGenImage get cmd => const SvgGenImage('assets/icons/cmd.svg'); + + /// File path: assets/icons/cmder-powershell.svg + SvgGenImage get cmderPowershell => + const SvgGenImage('assets/icons/cmder-powershell.svg'); + + /// File path: assets/icons/cmder.svg + SvgGenImage get cmder => const SvgGenImage('assets/icons/cmder.svg'); + + /// File path: assets/icons/cygwin.svg + SvgGenImage get cygwin => const SvgGenImage('assets/icons/cygwin.svg'); + + /// File path: assets/icons/debian.svg + SvgGenImage get debian => const SvgGenImage('assets/icons/debian.svg'); + + /// File path: assets/icons/docker.svg + SvgGenImage get docker => const SvgGenImage('assets/icons/docker.svg'); + + /// File path: assets/icons/git-bash.svg + SvgGenImage get gitBash => const SvgGenImage('assets/icons/git-bash.svg'); + + /// File path: assets/icons/kali.svg + SvgGenImage get kali => const SvgGenImage('assets/icons/kali.svg'); + + /// File path: assets/icons/linux.svg + SvgGenImage get linux => const SvgGenImage('assets/icons/linux.svg'); + + /// File path: assets/icons/msys2.svg + SvgGenImage get msys2 => const SvgGenImage('assets/icons/msys2.svg'); + + /// File path: assets/icons/open-euler.svg + SvgGenImage get openEuler => const SvgGenImage('assets/icons/open-euler.svg'); + + /// File path: assets/icons/oracle-linux.svg + SvgGenImage get oracleLinux => + const SvgGenImage('assets/icons/oracle-linux.svg'); + + /// File path: assets/icons/powershell-core.svg + SvgGenImage get powershellCore => + const SvgGenImage('assets/icons/powershell-core.svg'); + + /// File path: assets/icons/powershell.svg + SvgGenImage get powershell => + const SvgGenImage('assets/icons/powershell.svg'); + + /// File path: assets/icons/suse.svg + SvgGenImage get suse => const SvgGenImage('assets/icons/suse.svg'); + + /// File path: assets/icons/ubuntu.svg + SvgGenImage get ubuntu => const SvgGenImage('assets/icons/ubuntu.svg'); + + /// File path: assets/icons/vs2017.svg + SvgGenImage get vs2017 => const SvgGenImage('assets/icons/vs2017.svg'); + + /// File path: assets/icons/vs2019.svg + SvgGenImage get vs2019 => const SvgGenImage('assets/icons/vs2019.svg'); + + /// File path: assets/icons/vs2022.svg + SvgGenImage get vs2022 => const SvgGenImage('assets/icons/vs2022.svg'); + + /// List of all assets + List get values => [ + alma, + alpine, + clink, + cmd, + cmderPowershell, + cmder, + cygwin, + debian, + docker, + gitBash, + kali, + linux, + msys2, + openEuler, + oracleLinux, + powershellCore, + powershell, + suse, + ubuntu, + vs2017, + vs2019, + vs2022 + ]; +} + +class $AssetsImagesGen { + const $AssetsImagesGen(); + + /// File path: assets/images/ic_chrome_close.png + AssetGenImage get icChromeClose => + const AssetGenImage('assets/images/ic_chrome_close.png'); + + /// File path: assets/images/ic_chrome_maximize.png + AssetGenImage get icChromeMaximize => + const AssetGenImage('assets/images/ic_chrome_maximize.png'); + + /// File path: assets/images/ic_chrome_minimize.png + AssetGenImage get icChromeMinimize => + const AssetGenImage('assets/images/ic_chrome_minimize.png'); + + /// File path: assets/images/ic_chrome_unmaximize.png + AssetGenImage get icChromeUnmaximize => + const AssetGenImage('assets/images/ic_chrome_unmaximize.png'); + + /// List of all assets + List get values => + [icChromeClose, icChromeMaximize, icChromeMinimize, icChromeUnmaximize]; +} + +class Assets { + Assets._(); + + static const $AssetsIconsGen icons = $AssetsIconsGen(); + static const $AssetsImagesGen images = $AssetsImagesGen(); + static const AssetGenImage terminalPng = AssetGenImage('assets/terminal.png'); + static const SvgGenImage terminalSvg = SvgGenImage('assets/terminal.svg'); + + /// List of all assets + List get values => [terminalPng, terminalSvg]; +} + +class AssetGenImage { + const AssetGenImage(this._assetName); + + final String _assetName; + + Image image({ + Key? key, + AssetBundle? bundle, + ImageFrameBuilder? frameBuilder, + ImageErrorWidgetBuilder? errorBuilder, + String? semanticLabel, + bool excludeFromSemantics = false, + double? scale, + double? width, + double? height, + Color? color, + Animation? opacity, + BlendMode? colorBlendMode, + BoxFit? fit, + AlignmentGeometry alignment = Alignment.center, + ImageRepeat repeat = ImageRepeat.noRepeat, + Rect? centerSlice, + bool matchTextDirection = false, + bool gaplessPlayback = false, + bool isAntiAlias = false, + String? package, + FilterQuality filterQuality = FilterQuality.low, + int? cacheWidth, + int? cacheHeight, + }) { + return Image.asset( + _assetName, + key: key, + bundle: bundle, + frameBuilder: frameBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + scale: scale, + width: width, + height: height, + color: color, + opacity: opacity, + colorBlendMode: colorBlendMode, + fit: fit, + alignment: alignment, + repeat: repeat, + centerSlice: centerSlice, + matchTextDirection: matchTextDirection, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + package: package, + filterQuality: filterQuality, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + ); + } + + ImageProvider provider({ + AssetBundle? bundle, + String? package, + }) { + return AssetImage( + _assetName, + bundle: bundle, + package: package, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} + +class SvgGenImage { + const SvgGenImage(this._assetName); + + final String _assetName; + + SvgPicture svg({ + Key? key, + bool matchTextDirection = false, + AssetBundle? bundle, + String? package, + double? width, + double? height, + BoxFit fit = BoxFit.contain, + AlignmentGeometry alignment = Alignment.center, + bool allowDrawingOutsideViewBox = false, + WidgetBuilder? placeholderBuilder, + String? semanticsLabel, + bool excludeFromSemantics = false, + SvgTheme theme = const SvgTheme(), + ColorFilter? colorFilter, + Clip clipBehavior = Clip.hardEdge, + @deprecated Color? color, + @deprecated BlendMode colorBlendMode = BlendMode.srcIn, + @deprecated bool cacheColorFilter = false, + }) { + return SvgPicture.asset( + _assetName, + key: key, + matchTextDirection: matchTextDirection, + bundle: bundle, + package: package, + width: width, + height: height, + fit: fit, + alignment: alignment, + allowDrawingOutsideViewBox: allowDrawingOutsideViewBox, + placeholderBuilder: placeholderBuilder, + semanticsLabel: semanticsLabel, + excludeFromSemantics: excludeFromSemantics, + theme: theme, + colorFilter: colorFilter, + color: color, + colorBlendMode: colorBlendMode, + clipBehavior: clipBehavior, + cacheColorFilter: cacheColorFilter, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} diff --git a/lib/gen/fonts.gen.dart b/lib/gen/fonts.gen.dart new file mode 100644 index 0000000..d328894 --- /dev/null +++ b/lib/gen/fonts.gen.dart @@ -0,0 +1,15 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +class FontFamily { + FontFamily._(); + + /// Font family: Meslo LG L for Powerline + static const String mesloLGLForPowerline = 'Meslo LG L for Powerline'; +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..be06e58 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,25 @@ +{ + "app_name": "Fterm", + "settings": "Settings", + "select_lang": "Language", + "general": "General", + "theme": "Theme", + "hosts": "Hosts", + "keys": "SSH Keys", + "system": "System Language", + "en_US": "English", + "zh_CN": "简体中文", + "copy": "Copy", + "paste": "Paste", + "new_tab": "New Tab", + "received_file": "Received {filename}", + "@received_file": { + "placeholders": { + "filename": { + "type": "String", + "example": "example.png" + } + } + }, + "sync": "Sync" +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb new file mode 100644 index 0000000..761c6b0 --- /dev/null +++ b/lib/l10n/app_zh.arb @@ -0,0 +1,25 @@ +{ + "app_name": "Fterm", + "settings": "设置", + "select_lang": "语言", + "general": "通用", + "theme": "主题", + "hosts": "主机", + "keys": "SSH密钥", + "system": "系统语言", + "en_US": "English", + "zh_CN": "简体中文", + "copy": "复制", + "paste": "粘贴", + "new_tab": "创建", + "received_file": "完成接收: {filename}", + "@received_file": { + "placeholders": { + "filename": { + "type": "String", + "example": "example.png" + } + } + }, + "sync": "同步" +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..f49c01c --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,29 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bootstrap/launcher.dart'; +import 'package:fterm/bootstrap/options.dart'; +import 'package:fterm/bootstrap/runner.dart'; + + +Future main() async { + Bloc.observer = _AppBlocObserver(); + AppRunner.run( + Launcher(), + () => Future.value(const LaunchOptions()), + ); +} + +class _AppBlocObserver extends BlocObserver { + @override + void onError(BlocBase bloc, Object error, StackTrace stackTrace) { + super.onError(bloc, error, stackTrace); + } + + @override + void onEvent(Bloc bloc, Object? event) { + super.onEvent(bloc, event); + print("_AppBlocObserver: $event"); + // if (bloc is SshConfigBloc) { + // getIt().load(); + // } + } +} diff --git a/lib/model/color_item.dart b/lib/model/color_item.dart new file mode 100644 index 0000000..0ac9264 --- /dev/null +++ b/lib/model/color_item.dart @@ -0,0 +1,8 @@ +import 'package:xterm/xterm.dart'; + +class ColorItem { + final String name; + final TerminalTheme theme; + + ColorItem(this.name, this.theme); +} diff --git a/lib/model/shell.dart b/lib/model/shell.dart new file mode 100644 index 0000000..04cc16c --- /dev/null +++ b/lib/model/shell.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class Shell { + final String title; + final String cmd; + final List? args; + final Map? envs; + final Widget? icon; + + Shell(this.title, this.cmd, {this.icon, this.args, this.envs}); + + @override + String toString() { + return 'Shell{title: $title, cmd: $cmd, args: $args, envs: $envs}'; + } +} diff --git a/lib/model/ssh_config.dart b/lib/model/ssh_config.dart new file mode 100644 index 0000000..8728c11 --- /dev/null +++ b/lib/model/ssh_config.dart @@ -0,0 +1,88 @@ +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'ssh_config.g.dart'; + +@HiveType(typeId: 2) +enum AuthType { + @HiveField(1) + auto, + @HiveField(2) + password, + @HiveField(3) + key +} + +@JsonSerializable() +@HiveType(typeId: 1) +class SSHConfig { + @HiveField(1) + String id; // you can also use id = null to auto increment + + @HiveField(2, defaultValue: "") + String title; + @HiveField(3, defaultValue: "") + String host; + @HiveField(4, defaultValue: 0) + int port; + @HiveField(5, defaultValue: "") + String username; + @HiveField(6) + String? password; + @HiveField(7) + String? privateKey; + @HiveField(8) + String? passphrase; + @HiveField(9) + AuthType authType; + @HiveField(10) + int jumpServer = 0; + + SSHConfig({ + required this.id, + required this.title, + required this.host, + this.port = 22, + required this.username, + this.password, + this.privateKey, + this.passphrase, + this.authType = AuthType.auto, + this.jumpServer = 0, + }); + + SSHConfig copyWith({ + String? id, + String? title, + String? host, + int? port, + String? username, + String? password, + String? privateKey, + String? passphrase, + int? jumpServer, + }) { + return SSHConfig( + id: id ?? this.id, + title: title ?? this.title, + host: host ?? this.host, + port: port ?? this.port, + username: username ?? this.username, + password: password ?? this.password, + privateKey: privateKey ?? this.privateKey, + passphrase: passphrase ?? this.passphrase, + jumpServer: jumpServer ?? this.jumpServer, + ); + } + + @override + String toString() { + return 'SSHConfig{id: $id, title: $title, host: $host, port: $port, username: $username, password: $password, privateKey: $privateKey, passphrase: $passphrase, authType: $authType, jumpServer: $jumpServer}'; + } + + factory SSHConfig.fromJson(Map json) => + _$SSHConfigFromJson(json); + + /// Connect the generated [_$PersonToJson] function to the `toJson` method. + Map toJson() => _$SSHConfigToJson(this); +} diff --git a/lib/model/ssh_config.g.dart b/lib/model/ssh_config.g.dart new file mode 100644 index 0000000..59c4ebf --- /dev/null +++ b/lib/model/ssh_config.g.dart @@ -0,0 +1,149 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ssh_config.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class SSHConfigAdapter extends TypeAdapter { + @override + final int typeId = 1; + + @override + SSHConfig read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return SSHConfig( + id: fields[1] as String, + title: fields[2] == null ? '' : fields[2] as String, + host: fields[3] == null ? '' : fields[3] as String, + port: fields[4] == null ? 0 : fields[4] as int, + username: fields[5] == null ? '' : fields[5] as String, + password: fields[6] as String?, + privateKey: fields[7] as String?, + passphrase: fields[8] as String?, + authType: fields[9] as AuthType, + jumpServer: fields[10] as int, + ); + } + + @override + void write(BinaryWriter writer, SSHConfig obj) { + writer + ..writeByte(10) + ..writeByte(1) + ..write(obj.id) + ..writeByte(2) + ..write(obj.title) + ..writeByte(3) + ..write(obj.host) + ..writeByte(4) + ..write(obj.port) + ..writeByte(5) + ..write(obj.username) + ..writeByte(6) + ..write(obj.password) + ..writeByte(7) + ..write(obj.privateKey) + ..writeByte(8) + ..write(obj.passphrase) + ..writeByte(9) + ..write(obj.authType) + ..writeByte(10) + ..write(obj.jumpServer); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is SSHConfigAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class AuthTypeAdapter extends TypeAdapter { + @override + final int typeId = 2; + + @override + AuthType read(BinaryReader reader) { + switch (reader.readByte()) { + case 1: + return AuthType.auto; + case 2: + return AuthType.password; + case 3: + return AuthType.key; + default: + return AuthType.auto; + } + } + + @override + void write(BinaryWriter writer, AuthType obj) { + switch (obj) { + case AuthType.auto: + writer.writeByte(1); + break; + case AuthType.password: + writer.writeByte(2); + break; + case AuthType.key: + writer.writeByte(3); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AuthTypeAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SSHConfig _$SSHConfigFromJson(Map json) => SSHConfig( + id: json['id'] as String, + title: json['title'] as String, + host: json['host'] as String, + port: json['port'] as int? ?? 22, + username: json['username'] as String, + password: json['password'] as String?, + privateKey: json['privateKey'] as String?, + passphrase: json['passphrase'] as String?, + authType: $enumDecodeNullable(_$AuthTypeEnumMap, json['authType']) ?? + AuthType.auto, + jumpServer: json['jumpServer'] as int? ?? 0, + ); + +Map _$SSHConfigToJson(SSHConfig instance) => { + 'id': instance.id, + 'title': instance.title, + 'host': instance.host, + 'port': instance.port, + 'username': instance.username, + 'password': instance.password, + 'privateKey': instance.privateKey, + 'passphrase': instance.passphrase, + 'authType': _$AuthTypeEnumMap[instance.authType]!, + 'jumpServer': instance.jumpServer, + }; + +const _$AuthTypeEnumMap = { + AuthType.auto: 'auto', + AuthType.password: 'password', + AuthType.key: 'key', +}; diff --git a/lib/model/tab_item.dart b/lib/model/tab_item.dart new file mode 100644 index 0000000..e294d17 --- /dev/null +++ b/lib/model/tab_item.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; + +abstract class TabItem { + final title = ValueNotifier(null); + final content = ValueNotifier(null); + final icon = ValueNotifier(null); +} diff --git a/lib/service/sync_service.dart b/lib/service/sync_service.dart new file mode 100644 index 0000000..d50f30c --- /dev/null +++ b/lib/service/sync_service.dart @@ -0,0 +1,9 @@ +import 'dart:io'; + +abstract class SyncService { + SyncService(); + + Future pull(); + + Future push(); +} diff --git a/lib/service/webdav_sync_service.dart b/lib/service/webdav_sync_service.dart new file mode 100644 index 0000000..0b883af --- /dev/null +++ b/lib/service/webdav_sync_service.dart @@ -0,0 +1,94 @@ +import 'dart:collection'; +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:fterm/service/sync_service.dart'; +import 'package:hive/hive.dart'; +import 'package:injectable/injectable.dart'; +import 'package:webdav_client/webdav_client.dart'; + +import '../di/di.dart'; +import '../model/ssh_config.dart'; + +@Singleton(as: SyncService) +class WebDAVSyncService extends SyncService { + final FlutterSecureStorage storage; + + WebDAVSyncService(this.storage); + + Future get _client async { + String? webdav = await storage.read(key: "webdav"); + if (webdav == null) { + return null; + } + Map config = jsonDecode(webdav); + var client = newClient( + config['url']!, + user: config['username']!, + password: config['password']!, + debug: true, + ); + + // Set the public request headers + client.setHeaders({'accept-charset': 'utf-8'}); + + // Set the connection server timeout time in milliseconds. + client.setConnectTimeout(5000); + + // Set send data timeout time in milliseconds. + client.setSendTimeout(5000); + + // Set transfer data time in milliseconds. + client.setReceiveTimeout(5000); + + // Test whether the service can connect + try { + await client.ping(); + } catch (e) { + print('$e'); + } + return client; + } + + @PostConstruct() + void init() { + var box = getIt>(); + } + + @override + Future push() async { + var box = getIt>(); + var client = await _client; + if (client == null) return; + await client.mkdirAll("fterm/backup/"); + var map = box.toMap(); + client.write("backup-${DateTime.now().millisecondsSinceEpoch}", + Uint8List.fromList(jsonEncode(map).codeUnits)); + } + + @override + Future pull() async { + var client = await _client; + if (client == null) return; + var box = getIt>(); + + await client.mkdirAll("fterm/backup/"); + var files = await client + .readDir("fterm/backup/") + .then((value) => value.where((element) => !(element.isDir ?? false))); + files.forEach((element) { + print(element); + }); + print("read list"); + // var data = await client.read("fterm.backup"); + // var items = jsonDecode(String.fromCharCodes(data)) as Map; + // var data2 = items.map((key, value) { + // var config = SSHConfig.fromJson(value); + // return MapEntry(config.id, config); + // }); + // box.putAll(data2); + } +} diff --git a/lib/ui/connector/connector.dart b/lib/ui/connector/connector.dart new file mode 100644 index 0000000..976c3e3 --- /dev/null +++ b/lib/ui/connector/connector.dart @@ -0,0 +1,26 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; + +abstract class Connector { + Stream get output; + + StreamSink get input; + + Future get exitCode; + + void write(Uint8List data); + + Future connect(); + + void resize(width, height, pixelWidth, pixelHeight); + + bool get isRemote; + + String get title; + + Widget? get icon; + + Future dispose(); +} diff --git a/lib/ui/connector/local_connector.dart b/lib/ui/connector/local_connector.dart new file mode 100644 index 0000000..e06a237 --- /dev/null +++ b/lib/ui/connector/local_connector.dart @@ -0,0 +1,106 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_pty/flutter_pty.dart'; +import 'package:fterm/gen/assets.gen.dart'; + +import '../../model/shell.dart'; +import 'connector.dart'; + +class LocalConnector extends Connector { + final Shell? shell; + + LocalConnector({this.shell}); + + late Pty _pty; + + String? get _userHome => + Platform.environment['HOME'] ?? Platform.environment['USERPROFILE']; + final _outputController = StreamController(); + final _exitCode = StreamController(); + final _stdinController = StreamController(); + + String get executable => shell?.title ?? shell?.cmd ?? defaultShell; + + @override + Future connect() async { + debugPrint("LocalConnector==>${shell.toString()}"); + _pty = Pty.start( + executable, + arguments: shell?.args ?? [], + workingDirectory: _userHome, + environment: Platform.isWindows ? Map.from(Platform.environment) : null, + columns: 100, + rows: 100, + ackRead: false, + ); + _outputController.addStream(_pty.output); + _stdinController.stream.listen(_pty.write); + _exitCode.addStream(_pty.exitCode.asStream()); + + // _exitCode.stream.listen((event) { + // _stdinController.close(); + // _stdinController.close(); + // _outputController.close(); + // }); + } + + @override + Stream get output => _outputController.stream; + + @override + StreamSink get input => _stdinController.sink; + + @override + Future get exitCode => _exitCode.stream.first; + + @override + void write(Uint8List data) { + _pty.write(data); + } + + String get defaultShell { + if (Platform.isMacOS || Platform.isLinux) { + return Platform.environment['SHELL'] ?? 'bash'; + } + + if (Platform.isWindows) { + if (Process.runSync("where", ["pwsh.exe"]).exitCode == 0) { + return 'pwsh.exe'; + } + return 'powershell.exe'; + } + + return 'sh'; + } + + @override + void resize(width, height, pixelWidth, pixelHeight) { + _pty.resize(width, height); + } + + @override + bool get isRemote => false; + + @override + String get title => executable; + + @override + Widget? get icon { + if (shell?.icon != null) { + return shell?.icon; + } else { + if (Platform.isWindows) { + return Assets.icons.powershell.svg(width: 16, height: 16); + } + } + return null; + } + + @override + Future dispose() async { + _pty.kill(ProcessSignal.sigkill); + } +} diff --git a/lib/ui/connector/ssh_connector.dart b/lib/ui/connector/ssh_connector.dart new file mode 100644 index 0000000..d59af81 --- /dev/null +++ b/lib/ui/connector/ssh_connector.dart @@ -0,0 +1,105 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:dartssh2/dartssh2.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fterm/model/ssh_config.dart'; +import 'package:fterm/ui/connector/connector.dart'; + +class SSHConnector extends Connector { + final SSHConfig config; + final SSHConfig? jumpServer; + + SSHConnector(this.config, {this.jumpServer}); + + final _outputController = StreamController(); + late SSHSession _session; + SSHClient? _jmpServer; + late SSHClient _client; + + @override + Future connect() async { + SSHSocket sshSocket; + if (jumpServer != null) { + _jmpServer = + await SSHSocket.connect(jumpServer!.host, jumpServer!.port).then( + (jmpSocket) => SSHClient( + jmpSocket, + username: jumpServer!.username, + identities: [ + ...(jumpServer!.privateKey != null + ? SSHKeyPair.fromPem( + jumpServer!.privateKey!, + jumpServer!.passphrase, + ) + : []) + ], + onPasswordRequest: () => jumpServer!.password, + ), + ); + sshSocket = await _jmpServer!.forwardLocal(config.host, config.port); + } else { + sshSocket = await SSHSocket.connect(config.host, config.port); + } + + _client = SSHClient( + sshSocket, + username: config.username, + identities: [ + ...(config.privateKey != null + ? SSHKeyPair.fromPem( + config.privateKey!, + config.passphrase, + ) + : []) + ], + onPasswordRequest: () => config.password, + ); + _session = await _client.shell( + pty: const SSHPtyConfig( + width: 100, + height: 100, + ), + ); + _session.stdout.pipe(_outputController.sink); + // _outputController.addStream(_session.stdout); + } + + @override + Stream get output => _outputController.stream; + + @override + StreamSink get input => _session.stdin; + + @override + Future get exitCode => _session.done.then((value) { + return _session.exitCode ?? -99999; + }); + + @override + void write(Uint8List data) { + _outputController.add(data); + } + + @override + void resize(width, height, pixelWidth, pixelHeight) { + _session.resizeTerminal(width, height, pixelWidth, pixelHeight); + } + + @override + bool get isRemote => true; + + @override + String get title => config.title; + + @override + Widget? get icon => null; + + @override + Future dispose() async { + _session.kill(SSHSignal.KILL); + _client.close(); + _jmpServer?.close(); + _outputController.close(); + } +} diff --git a/lib/ui/connector/zmodem.dart b/lib/ui/connector/zmodem.dart new file mode 100644 index 0000000..351921a --- /dev/null +++ b/lib/ui/connector/zmodem.dart @@ -0,0 +1,312 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:zmodem/zmodem.dart'; + +export 'package:zmodem/zmodem.dart' show ZModemFileInfo; + +typedef ZModemInputHandler = void Function(String output); + +typedef ZModemOfferHandler = void Function(ZModemOffer offer); + +typedef ZModemRequestHandler = Future> Function(); + +abstract class ZModemOffer { + ZModemFileInfo get info; + + Stream accept(int offset); + + void skip(); +} + +class ZModemCallbackOffer implements ZModemOffer { + @override + final ZModemFileInfo info; + + final Stream Function(int offset) onAccept; + + final void Function()? onSkip; + + ZModemCallbackOffer(this.info, {required this.onAccept, this.onSkip}); + + @override + Stream accept(int offset) { + return onAccept(offset); + } + + @override + void skip() { + onSkip?.call(); + } +} + +final _zmodemSenderInit = '**\x18B0000000'.codeUnits; + +final _zmodemReceiverInit = '**\x18B0100000'.codeUnits; + +class ZModemMux { + /// Data from the underlying data channel. + final Stream stdout; + + /// The sink to write data to the underlying data channel. + final StreamSink> stdin; + + /// The callback to receive data that should be written to the terminal. + ZModemInputHandler? onTerminalInput; + + /// The callback to handle file receiving. If not set, all offers will be + /// skipped. + ZModemOfferHandler? onFileOffer; + + /// The callback to handle file sending. If not set, all requests will be + /// ignored. + ZModemRequestHandler? onFileRequest; + + ZModemMux({required this.stdin, required this.stdout}) { + _stdoutSubscription = stdout.listen(_handleStdout); + } + + /// Subscriptions to [stdout]. Used to pause/resume the stream when no more + /// space is available in local buffers. + late final StreamSubscription _stdoutSubscription; + + late final _terminalSink = StreamController>( + // onPause: _stdoutSubscription.pause, + // onResume: _stdoutSubscription.resume, + ) + ..stream + .transform(const Utf8Decoder(allowMalformed: true)) + .listen(onTerminalInput); + + /// Current ZModem session. If null, no session is active. + ZModemCore? _session; + + /// The sink to write data when receiving a file. If null, no file is being + /// received. + StreamController? _receiveSink; + + /// Offers to send to the remote peer. If null, no offers are being sent. + Iterator? _fileOffers; + + /// Writes terminal output to the underlying connection. [input] may be + /// buffered if a ZModem session is active. + void terminalWrite(String input) { + if (_session == null) { + stdin.add(utf8.encode(input) as Uint8List); + } + } + + /// This is the entry point of multiplexing, dispatching data to ZModem or + /// terminal depending on the current state. + void _handleStdout(Uint8List chunk) { + if (_session != null) { + _handleZModem(chunk); + return; + } + + if (_detectZModem(chunk)) { + return; + } + + _terminalSink.add(chunk); + } + + /// Detects a ZModem session in [chunk] and starts it if found. Returns true + /// if a session was started. + bool _detectZModem(Uint8List chunk) { + final index = chunk.listIndexOf(_zmodemSenderInit) ?? + chunk.listIndexOf(_zmodemReceiverInit); + + if (index != null) { + _terminalSink.add(Uint8List.sublistView(chunk, 0, index)); + + _session = ZModemCore( + onPlainText: (text) { + _terminalSink.add([text]); + }, + ); + + _handleZModem(Uint8List.sublistView(chunk, index)); + return true; + } + + return false; + } + + void _handleZModem(Uint8List chunk) async { + for (final event in _session!.receive(chunk)) { + /// remote is sz + if (event is ZFileOfferedEvent) { + _handleZFileOfferedEvent(event); + } else if (event is ZFileDataEvent) { + _handleZFileDataEvent(event); + } else if (event is ZFileEndEvent) { + await _handleZFileEndEvent(event); + } else if (event is ZSessionFinishedEvent) { + await _handleZSessionFinishedEvent(event); + } + + /// remote is rz + else if (event is ZReadyToSendEvent) { + await _handleFileRequestEvent(event); + } else if (event is ZFileAcceptedEvent) { + await _handleFileAcceptedEvent(event); + } else if (event is ZFileSkippedEvent) { + _handleFileSkippedEvent(event); + } + + _flush(); + } + + _flush(); + } + + void _handleZFileOfferedEvent(ZFileOfferedEvent event) { + final onFileOffer = this.onFileOffer; + + if (onFileOffer == null) { + _session!.skipFile(); + return; + } + + onFileOffer(_createRemoteOffer(event.fileInfo)); + } + + void _handleZFileDataEvent(ZFileDataEvent event) { + _receiveSink!.add(event.data as Uint8List); + } + + Future _handleZFileEndEvent(ZFileEndEvent event) async { + await _closeReceiveSink(); + } + + Future _handleZSessionFinishedEvent(ZSessionFinishedEvent event) async { + _flush(); + await _reset(); + } + + Future _handleFileRequestEvent(ZReadyToSendEvent event) async { + _fileOffers ??= (await onFileRequest?.call())?.iterator; + + _moveToNextOffer(); + } + + Future _handleFileAcceptedEvent(ZFileAcceptedEvent event) async { + final data = _fileOffers!.current.accept(event.offset); + var bytesSent = 0; + + await stdin.addStream( + data.transform( + StreamTransformer.fromHandlers( + handleData: (chunk, sink) { + bytesSent += chunk.length; + _session!.sendFileData(chunk); + sink.add(_session!.dataToSend()); + }, + ), + ), + ); + + _session!.finishSending(event.offset + bytesSent); + } + + void _handleFileSkippedEvent(ZFileSkippedEvent event) { + _fileOffers!.current.skip(); + _moveToNextOffer(); + } + + /// Sends next file offer if available, or closes the session if not. + void _moveToNextOffer() { + if (_fileOffers?.moveNext() != true) { + _closeSession(); + return; + } + + _session!.offerFile(_fileOffers!.current.info); + } + + /// Creates a [ZModemOffer] ƒrom the info from remote peer that can be used + /// by local client to accept or skip the file. + ZModemOffer _createRemoteOffer(ZModemFileInfo fileInfo) { + return ZModemCallbackOffer( + fileInfo, + onAccept: (offset) { + _session!.acceptFile(offset); + _flush(); + + _createReceiveSink(); + return _receiveSink!.stream; + }, + onSkip: () { + _session!.skipFile(); + _flush(); + }, + ); + } + + void _createReceiveSink() { + _receiveSink = StreamController( + onPause: () { + // _stdoutSubscription.pause(); + }, + onResume: () { + // _stdoutSubscription.resume(); + }, + ); + } + + Future _closeReceiveSink() async { + _stdoutSubscription.resume(); + await _receiveSink?.close(); + _receiveSink = null; + } + + /// Requests remote to close the session. + void _closeSession() { + _session!.finishSession(); + } + + /// Clears all ZModem state. + Future _reset() async { + await _closeReceiveSink(); + _fileOffers = null; + _session = null; + } + + /// Sends all pending data packets to the remote. No data is automatically + /// sent to the remote without calling this method. + void _flush() { + final dataToSend = _session?.dataToSend(); + if (dataToSend != null && dataToSend.isNotEmpty) { + stdin.add(dataToSend); + } + } +} + +extension ListExtension on List { + String dump() { + return map((e) => e.toRadixString(16).padLeft(2, '0')).join(' '); + } + + int? listIndexOf(List other, [int start = 0]) { + if (other.length + start > length) { + return null; + } + for (var i = start; i < length - other.length; i++) { + if (this[i] == other[0]) { + var found = true; + for (var j = 1; j < other.length; j++) { + if (this[i + j] != other[j]) { + found = false; + break; + } + } + if (found) { + return i; + } + } + } + return null; + } +} diff --git a/lib/ui/desktop_home.dart b/lib/ui/desktop_home.dart new file mode 100644 index 0000000..325bfc7 --- /dev/null +++ b/lib/ui/desktop_home.dart @@ -0,0 +1,173 @@ +import 'dart:io'; + +import 'package:fluent_ui/fluent_ui.dart' + show + CloseButtonVisibilityMode, + FluentApp, + FluentTheme, + FluentThemeData, + Tab, + TabView, + TabWidthBehavior; +import 'package:flutter/material.dart' hide Tab; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/bloc/home_tab_bloc.dart'; +import 'package:fterm/ui/connector/local_connector.dart'; +import 'package:fterm/ui/popover.dart'; +import 'package:fterm/ui/terminal_panel.dart'; +import 'package:fterm/ui/theme/app_theme.dart'; +import 'package:uuid/uuid.dart'; + +import '../di/di.dart'; +import '../model/tab_item.dart'; +import 'settings/settings_page.dart'; +import 'windows/window_caption.dart'; +import 'dart:developer' as developer; + +class DesktopHome extends StatefulWidget { + const DesktopHome({Key? key}) : super(key: key); + + @override + State createState() => _DesktopHomeState(); +} + +class _DesktopHomeState extends State + with ProfilesPop, AppThemeData { + @override + Widget build(BuildContext context) { + var configState = context.watch().state; + return BlocConsumer( + listener: (context, state) { + if (state.tabs.isEmpty) { + exit(0); + } + }, + buildWhen: (p, c) => p != c, + builder: (context, state) { + developer.log("DesktopHome.build"); + final tabs = state.tabs; + final current = state.currentIndex; + var childs = tabs.map((e) { + return Tab( + key: Key(const Uuid().v4()), + text: ValueListenableBuilder( + valueListenable: e.title, + builder: (context, content, child) { + return content ?? const Placeholder(); + }, + ), + icon: ValueListenableBuilder( + valueListenable: e.icon, + builder: (context, content, child) { + return content ?? const SizedBox.shrink(); + }, + ), + body: Container( + color: configState.currentColor.background, + child: ValueListenableBuilder( + valueListenable: e.content, + builder: (context, content, child) { + return content ?? const Placeholder(); + }, + ), + ), + onClosed: () { + getIt().add( + HomeTabEvent.remove(e), + ); + }, + ); + }).toList(); + return Container( + color: configState.currentColor.background, + child: Stack( + children: [ + TabView( + currentIndex: current, + tabWidthBehavior: TabWidthBehavior.equal, + shortcutsEnabled: false, + header: (Platform.isMacOS) + ? const SizedBox( + width: 50, + ) + : null, + footer: Container( + padding: EdgeInsets.only(right: Platform.isMacOS ? 50 : 195), + child: Builder(builder: (context) { + return IconButton( + padding: const EdgeInsets.all(5), + icon: const Icon(Icons.more_horiz), + onPressed: () { + showProfilesPop( + context, + themeData: + materialTheme(context, configState.currentColor), + ).then((connector) { + if (connector != null) { + getIt().add(HomeTabEvent.add( + TerminalTab(connector.title, connector, + icon: connector.icon))); + } + }); + }, + ); + }), + ), + closeButtonVisibility: tabs.length > 1 + ? CloseButtonVisibilityMode.always + : CloseButtonVisibilityMode.never, + onNewPressed: () { + var connector = LocalConnector(); + TabItem item = TerminalTab( + connector.executable, + connector, + icon: connector.icon, + ); + getIt().add(HomeTabEvent.add(item)); + }, + onChanged: (index) { + getIt().add( + HomeTabEvent.change(index), + ); + }, + onReorder: (int oldIndex, int newIndex) { + getIt().add( + HomeTabEvent.reorder(oldIndex, newIndex), + ); + }, + tabs: childs, + ), + if (!Platform.isMacOS) + const Align( + alignment: Alignment.topRight, + child: SizedBox( + width: 200, + height: kToolbarHeight / 1.4, + child: WindowCaption( + backgroundColor: Colors.transparent, + brightness: Brightness.dark, + ), + ), + ), + Positioned( + top: 0, + right: Platform.isMacOS ? 10 : 135, + child: IconButton( + icon: const Icon(Icons.settings), + onPressed: () { + getIt().add( + HomeTabEvent.add( + SettingsTab(), + ), + ); + }, + ), + ) + ], + ), + ); + }, + ); + } +} diff --git a/lib/ui/desktop_window.dart b/lib/ui/desktop_window.dart new file mode 100644 index 0000000..7dc2d3e --- /dev/null +++ b/lib/ui/desktop_window.dart @@ -0,0 +1,45 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/ui/desktop_home.dart'; + +import 'windows/draggeble_bar.dart'; + + +class DesktopWindow extends StatefulWidget { + const DesktopWindow({Key? key}) : super(key: key); + + @override + State createState() => _DesktopWindowState(); +} + +class _DesktopWindowState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + + return const Stack( + children: [ + DesktopHome(), + DraggebleAppBar( + brightness: Brightness.dark), + ], + ); + }, + ); + } +} diff --git a/lib/ui/popover.dart b/lib/ui/popover.dart new file mode 100644 index 0000000..0c4ae9d --- /dev/null +++ b/lib/ui/popover.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/ui/connector/connector.dart'; +import 'package:fterm/ui/connector/local_connector.dart'; +import 'package:fterm/ui/connector/ssh_connector.dart'; + +import '../bloc/home_tab_bloc.dart'; +import '../bloc/profiles_search_cubit.dart'; +import '../di/di.dart'; +import '../model/shell.dart'; +import '../model/ssh_config.dart'; +import 'terminal_panel.dart'; + +mixin ProfilesPop { + Future showProfilesPop(BuildContext context, + {ThemeData? themeData}) { + var themeData2 = themeData ?? ThemeData.dark(useMaterial3: true); + showDialog( + context: context, + builder: (c) => Dialog( + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return SizedBox( + width: constraints.maxWidth / 2.5, + height: constraints.maxHeight / 1.1, + child: _buildChild(themeData2), + ); + }), + ), + ); + return Future(() => null); + // return showPopover( + // context: context, + // bodyBuilder: (context) { + // return _buildChild(themeData2); + // }, + // onPop: () => print('Popover was popped!'), + // direction: PopoverDirection.bottom, + // width: 300, + // height: 400, + // arrowHeight: 5, + // arrowWidth: 7, + // // barrierColor: Colors.transparent, + // transitionDuration: const Duration(milliseconds: 50)); + // } + } +} + +Widget _buildChild(ThemeData themeData2) { + return Theme( + data: themeData2, + child: const Material( + child: PopContent(), + ), + ); +} + +class PopContent extends StatelessWidget { + const PopContent({Key? key}) : super(key: key); + + Widget _buildPanel(BuildContext context) { + var bloc = getIt(); + return BlocBuilder( + builder: (context, state) { + return ExpansionPanelList( + expansionCallback: (int index, bool isExpanded) { + getIt().expanded(index, !isExpanded); + }, + children: [ + ...state.items.map((e) { + return e.map( + hosts: (v) => ExpansionPanel( + headerBuilder: (context, isExpanded) => ListTile( + title: Text(v.header), + ), + body: Column( + children: v.hosts + .toList() + .where( + (value) => + state.keyword.trim().isEmpty || + value.title.contains(state.keyword), + ) + .map((e) => _buildSSH(e, bloc, context)) + .toList(), + ), + isExpanded: e.isExpanded, + ), + shells: (v) => ExpansionPanel( + headerBuilder: (context, isExpanded) => ListTile( + title: Text(v.header), + ), + body: Column( + children: v.shells + .toList() + .where( + (value) => + state.keyword.trim().isEmpty || + value.cmd.contains(state.keyword), + ) + .map((e) => _buildShell(e, bloc, context)) + .toList(), + ), + isExpanded: e.isExpanded, + )); + }), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + padding: const EdgeInsets.all(5), + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + ), + onChanged: (v) { + context.read().search(v); + }, + ), + ), + Expanded( + child: SingleChildScrollView( + child: _buildPanel(context), + ), + ), + ], + ); + } + + Widget _buildShell(Shell e, HomeTabBloc bloc, BuildContext context) { + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 0) + .copyWith(left: 30), + // leading: const Icon(Icons.settings), + title: Text(e.title), + leading: const Icon(Icons.terminal), + onTap: () { + var connector = LocalConnector(shell: e); + bloc.add( + HomeTabEvent.add( + TerminalTab(connector.executable, connector), + ), + ); + Navigator.pop(context, connector); + }, + ); + } + + Widget _buildSSH(SSHConfig e, HomeTabBloc bloc, BuildContext context) { + return ListTile( + contentPadding: + const EdgeInsets.symmetric(horizontal: 16).copyWith(left: 30), + // leading: const Icon(Icons.settings), + title: Text(e.title), + subtitle: Text("${e.username}@${e.host}:${e.port}"), + leading: const Icon(Icons.computer), + onTap: () { + bloc.add( + HomeTabEvent.add( + TerminalTab(e.title, SSHConnector(e)), + ), + ); + Navigator.pop(context, SSHConnector(e)); + }, + ); + } +} diff --git a/lib/ui/settings/general_page.dart b/lib/ui/settings/general_page.dart new file mode 100644 index 0000000..b296add --- /dev/null +++ b/lib/ui/settings/general_page.dart @@ -0,0 +1,70 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/di/di.dart'; +import 'package:fterm/utils/string_ext.dart'; + +import 'package:settings_ui/settings_ui.dart'; +import 'package:flutter_gen/gen_l10n/SS.dart'; + +class GeneralPage extends StatelessWidget { + const GeneralPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var configState = context.watch().state; + var theme = configState.currentColor; + var locale = configState.locale; + return SettingsList( + darkTheme: SettingsThemeData( + settingsListBackground: theme.background.toAccentColor().dark, + settingsSectionBackground: theme.background.toAccentColor().light, + ), + sections: [ + SettingsSection( + tiles: [ + SettingsTile( + leading: const Icon(FluentIcons.landscape_orientation), + title: Text(SS.of(context).select_lang), + trailing: null, + value: ComboBox( + value: locale?.toString() ?? "system", + items: [ + ComboBoxItem( + value: "system", + child: Text(SS.of(context).system), + ), + ..._langs.keys.map((e) { + return ComboBoxItem( + value: e.toString(), + child: Text(_langs[e]!), + ); + }) + ], + onChanged: (e) { + if (e == null || e == "system") { + context.read().clearLocal(); + } else { + context.read().setLocal(e.toLocale()); + } + }, + ), + ), + SettingsTile.switchTile( + initialValue: configState.showFPS, + onToggle: (v) { + getIt().showFPS(v); + }, + title: const Text("显示FPS"), + ), + ], + ), + ], + ); + } +} + +var _langs = { + const Locale('en', 'US'): "English", + const Locale('zh', 'CN'): "简体中文", +}; diff --git a/lib/ui/settings/hosts/add_host_page.dart b/lib/ui/settings/hosts/add_host_page.dart new file mode 100644 index 0000000..d5c02f3 --- /dev/null +++ b/lib/ui/settings/hosts/add_host_page.dart @@ -0,0 +1,332 @@ +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:fterm/bloc/ssh_config_bloc.dart'; +import 'package:fterm/di/di.dart'; +import 'package:fterm/model/ssh_config.dart'; +import 'package:go_router/go_router.dart'; +import 'package:uuid/uuid.dart'; + +import '../../widget/radio.dart'; + +class AddHostPage extends StatefulWidget { + final SSHConfig? config; + + const AddHostPage({Key? key, this.config}) : super(key: key); + + @override + State createState() => _AddHostPageState(); +} + +class _PortTextInputFormatter extends TextInputFormatter { + bool isNumeric(String? s) { + if (s == null) { + return false; + } + return int.tryParse(s) != null; + } + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + if (!isNumeric(newValue.text)) { + return oldValue; + } + var i = int.parse(newValue.text); + if (i > 0 && i <= 65535) { + return newValue; + } else { + return oldValue; + } + } +} + +class _AddHostPageState extends State { + AuthType _authType = AuthType.auto; + final TextEditingController _keyController = TextEditingController(); + final GlobalKey _globalKey = GlobalKey(); + late SSHConfig config; + + @override + void initState() { + config = widget.config ?? + SSHConfig( + id: const Uuid().v4().toString(), + title: "", + host: "", + username: "", + port: 22); + _keyController.text = config.privateKey ?? ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.config == null ? "添加主机" : "修改主机"), + actions: [ + IconButton( + onPressed: () { + if (_globalKey.currentState?.validate() == true) { + _globalKey.currentState?.save(); + getIt().add(SshConfigEvent.add(config)); + context.pop(); + } + }, + icon: const Icon( + Icons.save, + size: 28, + )) + ], + ), + body: Center( + child: Container( + width: 500, + padding: const EdgeInsets.all(18.0), + child: Form( + key: _globalKey, + child: ListView( + children: [ + TextFormField( + initialValue: config.title, + decoration: InputDecoration( + isDense: true, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + border: const OutlineInputBorder(), + labelText: "标题", + ), + onSaved: (v) => config.title = v!, + ), + Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( + children: [ + Expanded( + child: TextFormField( + initialValue: config.host, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + isDense: true, + hintText: "192.168.1.1", + border: const OutlineInputBorder(), + labelText: "主机地址", + ), + validator: (v) { + if (v?.isEmpty == true) { + EasyLoading.showError("主机地址不能为空"); + } + return null; + }, + onSaved: (v) => config.host = v!, + ), + ), + Container( + padding: const EdgeInsets.only(left: 5), + width: 85, + child: TextFormField( + initialValue: "${config.port}", + inputFormatters: [ + _PortTextInputFormatter(), + ], + decoration: InputDecoration( + isDense: true, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + border: const OutlineInputBorder(), + hintText: "22", + labelText: "端口", + ), + onSaved: (v) => config.port = int.tryParse(v!) ?? 0, + validator: (v) { + if (v?.isEmpty == true) { + EasyLoading.showError("端口不能为空"); + } + return null; + }, + ), + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 10), + child: TextFormField( + initialValue: config.username, + decoration: InputDecoration( + isDense: true, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + border: const OutlineInputBorder(), + hintText: "root", + labelText: "用户名", + ), + onSaved: (v) => config.username = v!, + validator: (v) { + if (v?.isEmpty == true) { + EasyLoading.showError("用户名不能为空"); + } + return null; + }, + ), + ), + Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only(top: 20, bottom: 1), + child: Row( + children: [ + const Text("验证方式:"), + Padding( + padding: const EdgeInsets.only(left: 20), + child: RadioFormGroup( + config.authType, + onChanged: (value) { + //rebuild current form field + setState(() { + _authType = value ?? AuthType.auto; + }); + }, + onSaved: (v) { + config.authType = v!; + }, + items: const [ + RadioItem( + AuthType.auto, + title: Text("自动"), + ), + RadioItem( + AuthType.password, + title: Text("密码"), + ), + RadioItem( + AuthType.key, + title: Text("秘钥"), + ) + ], + ), + ) + ], + ), + ), + ), + if (_authType == AuthType.auto || + _authType == AuthType.password) + Padding( + padding: const EdgeInsets.only(top: 10), + child: TextFormField( + obscureText: true, + initialValue: config.password, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + isDense: true, + border: const OutlineInputBorder(), + labelText: "密码", + ), + onChanged: (v) => config.password = v, + validator: (v) { + if ((config.password == null || + config.password?.isEmpty == true) && + (config.privateKey == null || + config.privateKey?.isEmpty == true)) { + EasyLoading.showError("至少填写一种认证方式"); + } + return null; + }, + ), + ), + if (_authType == AuthType.auto || _authType == AuthType.key) + Padding( + padding: const EdgeInsets.only(top: 10), + child: SingleChildScrollView( + child: TextFormField( + onChanged: (v) => config.privateKey = v, + validator: (v) { + if ((config.password == null || + config.password?.isEmpty == true) && + (config.privateKey == null || + config.privateKey?.isEmpty == true)) { + EasyLoading.showError("至少填写一种认证方式"); + } + return null; + }, + keyboardType: TextInputType.multiline, + maxLines: 10, + minLines: 10, + controller: _keyController, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).hintColor, + ), + ), + isDense: true, + border: const OutlineInputBorder(), + labelText: "秘钥", + hintText: "鼠标右键可以直接选择秘钥文件"), + contextMenuBuilder: (BuildContext context, + EditableTextState editableTextState) { + final TextEditingValue value = + editableTextState.textEditingValue; + final List buttonItems = + editableTextState.contextMenuButtonItems; + + buttonItems.insert( + 0, + ContextMenuButtonItem( + label: '选择文件', + onPressed: () async { + ContextMenuController.removeAny(); + FilePickerResult? result = + await FilePicker.platform.pickFiles( + dialogTitle: "选择秘钥", + initialDirectory: + Platform.environment['HOME'] ?? + Platform.environment['USERPROFILE'], + ); + if (result != null) { + File file = File(result.files.first.path!); + var keyBody = await file.readAsString(); + _keyController.text = keyBody; + } else { + print("取消了选择"); + } + }, + )); + return AdaptiveTextSelectionToolbar.buttonItems( + anchors: editableTextState.contextMenuAnchors, + buttonItems: buttonItems, + ); + }, + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/settings/hosts/list_host_page.dart b/lib/ui/settings/hosts/list_host_page.dart new file mode 100644 index 0000000..452cbc1 --- /dev/null +++ b/lib/ui/settings/hosts/list_host_page.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../bloc/ssh_config_bloc.dart'; + +class HostListPage extends StatelessWidget { + const HostListPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var state = context.watch().state; + return Scaffold( + appBar: AppBar( + title: const Text("主机列表"), + actions: [ + IconButton( + onPressed: () { + // Navigator.of(context).pushNamed("/add"); + context.push("/add"); + // context.go("/add") + }, + icon: const Icon( + Icons.add, + size: 28, + )) + ], + ), + body: ListView( + children: [ + ...state.configs.map( + (e) => ListTile( + onTap: () { + context.push( + "/add", + extra: e, + ); + }, + leading: const Icon(Icons.computer), + title: Text(e.title), + subtitle: Text("${e.username}@${e.host}:${e.port}"), + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/settings/hosts_page.dart b/lib/ui/settings/hosts_page.dart new file mode 100644 index 0000000..9b297fd --- /dev/null +++ b/lib/ui/settings/hosts_page.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/model/ssh_config.dart'; +import 'package:go_router/go_router.dart'; + +import '../theme/app_theme.dart'; +import 'hosts/add_host_page.dart'; +import 'hosts/list_host_page.dart'; + +class HostPage extends StatelessWidget with AppThemeData { + const HostPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final router = GoRouter( + routes: [ + GoRoute( + path: '/', + name: "/", + builder: (context, state) => const HostListPage(), + ), + GoRoute( + path: '/add', + name: "/add", + builder: (context, state) { + var config = state.extra as SSHConfig?; + return AddHostPage( + config: config, + ); + }, + ), + ], + ); + var colors = context.watch().state.currentColor; + return MaterialApp.router( + debugShowCheckedModeBanner: false, + theme: materialTheme(context, colors), + routerConfig: router, + ); + } +} diff --git a/lib/ui/settings/settings_page.dart b/lib/ui/settings/settings_page.dart new file mode 100644 index 0000000..4b7236f --- /dev/null +++ b/lib/ui/settings/settings_page.dart @@ -0,0 +1,86 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/ssh_config_bloc.dart'; +import 'package:fterm/model/tab_item.dart'; + +import '../../bloc/app_config_cubit.dart'; +import 'sync/sync_page.dart'; +import 'theme_page.dart'; +import 'general_page.dart'; +import 'hosts_page.dart'; +import 'package:flutter_gen/gen_l10n/SS.dart'; + +class SettingsTab extends TabItem { + SettingsTab() { + title.value = const Text("Settings"); + content.value = const SettingPage(); + } +} + +class SettingPage extends StatefulWidget { + const SettingPage({Key? key}) : super(key: key); + + @override + State createState() => _SettingPageState(); +} + +class _SettingPageState extends State { + int topIndex = 0; + var displayMode = PaneDisplayMode.open; + + @override + Widget build(BuildContext context) { + var configState = context.watch().state; + var theme = configState.currentColor; + return BlocBuilder( + builder: (context, state) { + var ss = SS.of(context); + return Container( + padding: const EdgeInsets.only(top: 10), + child: NavigationView( + pane: NavigationPane( + selected: topIndex, + size: const NavigationPaneSize(openMaxWidth: 250), + onChanged: (index) => setState(() => topIndex = index), + displayMode: displayMode, + items: [ + PaneItem( + icon: const Icon(FluentIcons.apps_content), + title: Text(ss.general), + body: Container( + color: theme.background, + child: const GeneralPage(), + ), + ), + PaneItem( + icon: const Icon(FluentIcons.apps_content), + title: Text(ss.theme), + body: Container( + color: theme.background, + child: const ThemePage(), + ), + ), + PaneItem( + icon: const Icon(FluentIcons.connect_contacts), + title: Text(ss.hosts), + body: Container( + color: theme.background, + child: const HostPage(), + ), + ), + PaneItem( + icon: const Icon(FluentIcons.sync), + title: Text(ss.sync), + body: Container( + color: theme.background, + child: Text("coming soon!"), + ), + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/settings/sync/sync_page.dart b/lib/ui/settings/sync/sync_page.dart new file mode 100644 index 0000000..96b26cd --- /dev/null +++ b/lib/ui/settings/sync/sync_page.dart @@ -0,0 +1,29 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/di/di.dart'; + +import '../../../bloc/app_config_cubit.dart'; +import '../../../service/sync_service.dart'; +import '../../theme/app_theme.dart'; + +class SyncPage extends StatelessWidget with AppThemeData { + const SyncPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var colors = context.watch().state.currentColor; + return MaterialApp( + debugShowCheckedModeBanner: false, + theme: materialTheme(context, colors), + home: Scaffold( + body: Button( + child: Text("同步"), + onPressed: () async { + var service=getIt(); + await service.pull(); + }), + ), + ); + } +} diff --git a/lib/ui/settings/theme_page.dart b/lib/ui/settings/theme_page.dart new file mode 100644 index 0000000..4a68fbf --- /dev/null +++ b/lib/ui/settings/theme_page.dart @@ -0,0 +1,334 @@ + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:fterm/di/di.dart'; +import 'package:xterm/xterm.dart'; + + + +class ThemePage extends StatelessWidget { + const ThemePage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return _ThemePageNavigator( + navigatorKey: GlobalKey(), + ); + } +} + +class _ThemePageNavigator extends StatelessWidget { + const _ThemePageNavigator({Key? key, required this.navigatorKey}) + : super(key: key); + final GlobalKey navigatorKey; + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + initialRoute: '/', + onGenerateRoute: (RouteSettings routeSettings) { + return FluentPageRoute( + settings: routeSettings, + builder: (context) { + return getPage(routeSettings.name); + }); + }); + } + + Widget getPage(String? url) { + switch (url) { + case "/color": + return const _ColorConfigPage(); + case "/": + default: + return const _ColorListPage(); + } + } +} + +class _ColorListPage extends StatefulWidget { + const _ColorListPage({Key? key}) : super(key: key); + + @override + State<_ColorListPage> createState() => _ColorListPageState(); +} + +extension aaa on List { + filter(bool Function(E element) test) { + return where((element) => !test(element)); + } +} + +class _ColorListPageState extends State<_ColorListPage> { + String kw = ""; + + @override + Widget build(BuildContext context) { + var configState = context.watch().state; + var current = configState.currentColor; + var currentName = configState.currentColorName; + var s = configState.colorSchemes; + return ScaffoldPage( + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "当前:$currentName", + ), + SizedBox( + width: double.maxFinite, + height: 130, + child: _buildPreviewView(current), + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 50), + child: TextBox( + prefix: const Icon(FluentIcons.search), + placeholder: "搜索配色方案", + onChanged: (v) { + setState(() { + kw = v; + }); + }, + ), + ), + ...s.entries + .where((element) => element.key.contains(kw)) + .map((e) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: _buildColorItem(context, e, currentName), + )) + ], + ), + ), + ); + } + + Widget _buildColorItem(BuildContext context, + MapEntry item, String current) { + return GestureDetector( + onTap: () { + getIt().setCurrentColorScheme(item.key); + }, + child: Container( + color: item.key == current ? Colors.blue : Colors.grey, + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item.key), + SizedBox( + width: double.maxFinite, + height: 130, + child: _buildPreviewView(item.value), + ) + ], + ), + ), + ); + } + + Widget _buildPreviewView(TerminalTheme colors) { + var textStyle = DefaultTextStyle.of(context).style.copyWith( + backgroundColor: colors.background, + color: colors.foreground, + ); + return Container( + color: colors.background, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + // text: "user@develop-pc\$ ls ", + style: textStyle, + children: [ + TextSpan(text: 'henjue', style: TextStyle(color: colors.green)), + TextSpan(text: '@', style: TextStyle(color: colors.cyan)), + TextSpan( + text: 'develop-pc', style: TextStyle(color: colors.blue)), + TextSpan( + text: '\$', + style: TextStyle( + fontWeight: FontWeight.bold, color: colors.red)), + const TextSpan(text: ' '), + const TextSpan(text: 'ls'), + TextSpan( + text: "\u00A0\u00A0", + style: TextStyle( + // color: colors.cursor, + background: Paint()..color = colors.red, + ), + ), + ], + ), + ), + RichText( + text: TextSpan( + text: "-rwxr-xr-x 1 root ", + style: textStyle, + children: [ + TextSpan( + text: "Documents", + style: TextStyle( + color: colors.yellow, + ), + ), + ], + ), + ), + RichText( + text: TextSpan( + text: "-rwxr-xr-x 1 root ", + style: textStyle, + children: [ + TextSpan( + text: "Downlodas", + style: TextStyle( + color: colors.black, + background: Paint()..color = colors.green, + ), + ), + ], + ), + ), + RichText( + text: TextSpan( + text: "-rwxr-xr-x 1 root ", + style: textStyle, + children: [ + TextSpan( + text: "Pictures", + style: TextStyle( + color: colors.black, + background: Paint()..color = colors.brightBlack, + ), + ), + ], + ), + ), + RichText( + text: TextSpan( + text: "-rwxr-xr-x 1 root ", + style: textStyle, + children: [ + TextSpan( + text: "Music", + style: TextStyle( + color: colors.black, + background: Paint()..color = colors.brightBlue, + ), + ), + ], + ), + ), + RichText( + text: TextSpan( + text: "-rwxr-xr-x 1 root ", + style: textStyle, + children: [ + TextSpan( + text: "実行可能ファイル", + style: TextStyle( + color: colors.green, + ), + ), + ], + ), + ), + // RichText( + // text: TextSpan( + // text: "-rwxr-xr-x 1 root ", + // style: textStyle, + // children: [ + // TextSpan( + // text: "sym ", + // style: TextStyle( + // color: colors.cyan, + // ), + // ), + // const TextSpan( + // text: "->", + // ), + // TextSpan( + // text: " link", + // style: TextStyle( + // color: colors.red, + // ), + // ), + // ], + // ), + // ), + // RichText( + // text: TextSpan( + // style: textStyle, + // children: [ + // TextSpan( + // text: "Icons:", + // style: textStyle.copyWith(fontWeight: FontWeight.bold), + // ), + // TextSpan( + // text: "  ", + // style: textStyle.copyWith( + // fontFamily: FontFamily.mesloLGLForPowerline), + // ), + // TextSpan( + // text: " ", + // style: textStyle, + // ), + // TextSpan( + // text: "  Powerline ", + // style: TextStyle( + // color: colors.black, + // background: Paint()..color = colors.red, + // ), + // ), + // TextSpan( + // text: " ", + // style: TextStyle( + // color: colors.red, + // ), + // ), + // ], + // ), + // ), + ], + ), + ); + } +} + +class _ColorConfigPage extends StatelessWidget { + const _ColorConfigPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ScaffoldPage( + header: PageHeader( + leading: Button( + child: const Icon(FluentIcons.back), + onPressed: () { + Navigator.of(context).pop(); + }), + ), + content: Button( + child: const Text("color"), + onPressed: () { + Navigator.of(context).pushNamed("/color"); + }, + ), + ); + } +} diff --git a/lib/ui/shortcut/global_actions.dart b/lib/ui/shortcut/global_actions.dart new file mode 100644 index 0000000..e152cea --- /dev/null +++ b/lib/ui/shortcut/global_actions.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:fterm/ui/connector/local_connector.dart'; +import 'package:fterm/ui/shortcut/intents.dart'; +import 'package:fterm/ui/terminal_panel.dart'; + +import '../../bloc/home_tab_bloc.dart'; +import '../../di/di.dart'; +import '../popover.dart'; + +class LoggingActionDispatcher extends ActionDispatcher { + @override + Object? invokeAction( + covariant Action action, + covariant Intent intent, [ + BuildContext? context, + ]) { + print('Action invoked: $action($intent) from $context'); + super.invokeAction(action, intent, context); + return null; + } +} + +class GlobalActions extends StatelessWidget with ProfilesPop { + const GlobalActions({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Actions( + dispatcher: LoggingActionDispatcher(), + actions: { + OpenSettingIntent: + CallbackAction(onInvoke: (intent) => null), + OpenTabIntent: CallbackAction(onInvoke: (intent) { + var localConnector = LocalConnector(); + getIt().add( + HomeTabEvent.add( + TerminalTab( + localConnector.title, + localConnector, + icon: localConnector.icon, + ), + ), + ); + return null; + }), + CloseTabIntent: CallbackAction(onInvoke: (intent) { + var tab = getIt() + .state + .tabs[getIt().state.currentIndex]; + getIt().add(HomeTabEvent.remove(tab)); + return null; + }), + }, + child: child, + ); + } +} diff --git a/lib/ui/shortcut/global_shortcuts.dart b/lib/ui/shortcut/global_shortcuts.dart new file mode 100644 index 0000000..7b3ffc5 --- /dev/null +++ b/lib/ui/shortcut/global_shortcuts.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'intents.dart'; +import 'shortcuts.dart' as shortcuts; + +class GlobalShortcuts extends StatelessWidget { + const GlobalShortcuts({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Shortcuts( + shortcuts: { + shortcuts.tabOpen: const OpenTabIntent(), + shortcuts.tabClose: const CloseTabIntent(), + shortcuts.openSettings: const OpenSettingIntent(), + }, + child: child, + ); + } +} diff --git a/lib/ui/shortcut/intents.dart b/lib/ui/shortcut/intents.dart new file mode 100644 index 0000000..7d198c2 --- /dev/null +++ b/lib/ui/shortcut/intents.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +class OpenSettingIntent extends Intent { + const OpenSettingIntent(); +} + +class OpenTabIntent extends Intent { + const OpenTabIntent(); +} + +class CloseTabIntent extends Intent { + const CloseTabIntent(); +} + diff --git a/lib/ui/shortcut/shortcuts.dart b/lib/ui/shortcut/shortcuts.dart new file mode 100644 index 0000000..0e074ad --- /dev/null +++ b/lib/ui/shortcut/shortcuts.dart @@ -0,0 +1,38 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:fterm/utils/target_platform.dart'; + +SingleActivator get openSettings { + return defaultTargetPlatform.isApple + ? const SingleActivator( + LogicalKeyboardKey.comma, + meta: true, + ) + : const SingleActivator( + LogicalKeyboardKey.comma, + control: true, + ); +} + +SingleActivator get tabOpen { + return defaultTargetPlatform.isApple + ? const SingleActivator( + LogicalKeyboardKey.keyT, + meta: true, + ) + : const SingleActivator( + LogicalKeyboardKey.keyT, + alt: true, + shift: true, + ); +} + +SingleActivator get tabClose { + return defaultTargetPlatform.isApple + ? const SingleActivator( + LogicalKeyboardKey.keyW, + meta: true, + ) + : const SingleActivator(LogicalKeyboardKey.keyW, shift: true, alt: true); +} diff --git a/lib/ui/ssh_page.dart b/lib/ui/ssh_page.dart new file mode 100644 index 0000000..b56ac2d --- /dev/null +++ b/lib/ui/ssh_page.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fterm/bloc/ssh_config_bloc.dart'; +import 'package:fterm/model/ssh_config.dart'; +import 'package:uuid/uuid.dart'; + +class SSHPage extends StatefulWidget { + final SSHConfig? config; + + const SSHPage({Key? key, this.config}) : super(key: key); + + @override + State createState() => _SSHPageState(); +} + +class _SSHPageState extends State { + final GlobalKey _formKey = GlobalKey(); + + SSHConfig get _config => + widget.config ?? + SSHConfig( + id: const Uuid().v4().toString(), title: "", host: "", username: ""); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData.dark(useMaterial3: true), + home: Scaffold( + body: Center( + child: SizedBox( + width: 300, + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + initialValue: _config.title, + decoration: const InputDecoration( + icon: Icon(Icons.title), + hintText: '输入配置名', + labelText: '名字', + ), + validator: (v) { + if (v?.isEmpty == true) { + return "配置名不能为空"; + } + return null; + }, + onSaved: (v) { + _config.title = v ?? ""; + }, + ), + TextFormField( + initialValue: _config.host, + decoration: const InputDecoration( + icon: Icon(Icons.link), + hintText: '输入域名或IP,如 192.168.50.1', + labelText: '地址', + ), + validator: (v) { + if (v?.isEmpty == true) { + return "地址不能为空"; + } + return null; + }, + onSaved: (v) { + _config.host = v ?? ""; + }, + ), + TextFormField( + initialValue: _config.username, + decoration: const InputDecoration( + icon: Icon(Icons.link), + hintText: '登录用户名', + labelText: '用户名', + ), + validator: (v) { + if (v?.isEmpty == true) { + return "用户名不能为空"; + } + return null; + }, + onSaved: (v) { + _config.username = v ?? ""; + }, + ), + TextFormField( + initialValue: _config.password, + decoration: const InputDecoration( + icon: Icon(Icons.link), + hintText: '登录密码', + labelText: '密码', + ), + validator: (v) { + if (v?.isEmpty == true) { + return "密码不能为空"; + } + return null; + }, + onSaved: (v) { + _config.password = v; + }, + ), + // 登录按钮 + Padding( + padding: const EdgeInsets.only(top: 28.0), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + child: const Padding( + padding: EdgeInsets.all(16.0), + child: Text("保存"), + ), + onPressed: () { + var formState = + _formKey.currentState as FormState; + if ((formState).validate()) { + formState.save(); + context + .read() + .add(SshConfigEvent.add(_config)); + //验证通过提交数据 + } + }, + ), + ), + ], + ), + ) + ], + )), + ), + ), + ), + ); + } +} diff --git a/lib/ui/term_app.dart b/lib/ui/term_app.dart new file mode 100644 index 0000000..a45e2d5 --- /dev/null +++ b/lib/ui/term_app.dart @@ -0,0 +1,67 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; + + +import 'desktop_window.dart'; +import 'shortcut/global_actions.dart'; +import 'shortcut/global_shortcuts.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_gen/gen_l10n/SS.dart'; + +class TermApp extends StatelessWidget { + const TermApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var configState = context.watch().state; + var locale = configState.locale; + var theme = configState.currentColor; + if (kDebugMode) { + print("current locale: ${locale.toString()}"); + } + Widget widget = const GlobalShortcuts( + child: GlobalActions( + child: DesktopWindow(), + ), + ); + var background = theme.background; + var bgAccentColor = background.toAccentColor(); + var foreground = theme.foreground; + return FluentApp( + debugShowCheckedModeBanner: false, + themeMode: ThemeMode.dark, + theme: FluentThemeData.light(), + darkTheme: FluentThemeData.dark().copyWith( + animationCurve: Curves.bounceIn, + accentColor: bgAccentColor, + cardColor: background, + navigationPaneTheme: NavigationPaneThemeData( + backgroundColor: bgAccentColor, + highlightColor: foreground, + ), + resources: ResourceDictionary.dark( + textFillColorPrimary: foreground, + textFillColorSecondary: foreground, + textFillColorTertiary: foreground, + textFillColorInverse: foreground, + subtleFillColorTertiary: bgAccentColor.dark, + subtleFillColorSecondary: bgAccentColor.light, + subtleFillColorTransparent: bgAccentColor.dark, + ), + ), + localizationsDelegates: const [ + SS.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: SS.supportedLocales, + locale: locale, + builder: EasyLoading.init(), + home: widget, + ); + } +} diff --git a/lib/ui/terminal_panel.dart b/lib/ui/terminal_panel.dart new file mode 100644 index 0000000..6eb2fa1 --- /dev/null +++ b/lib/ui/terminal_panel.dart @@ -0,0 +1,309 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:fterm/bloc/app_config_cubit.dart'; +import 'package:path/path.dart' as path; +import 'package:fterm/bloc/home_tab_bloc.dart'; +import 'package:fterm/di/di.dart'; +import 'package:fterm/model/tab_item.dart'; +import 'package:fterm/ui/connector/connector.dart'; +import 'package:fterm/ui/popover.dart'; +import 'package:native_context_menu/native_context_menu.dart'; +import 'package:xterm/xterm.dart'; +import 'package:flutter_gen/gen_l10n/SS.dart'; + +import 'connector/local_connector.dart'; +import 'connector/zmodem.dart'; +import 'dart:developer' as developer; + +class TerminalTab extends TabItem { + final Connector _connector; + + TerminalTab(String defaultTitle, Connector connector, {Widget? icon}) + : _connector = connector { + super.title.value = Text(defaultTitle); + super.content.value = TerminalPanel(this); + super.icon.value = icon; + } + + _init(void Function(String message) onClose) async { + developer.log("TerminalTab._init"); + await _connector.connect(); + _connector.exitCode.then((code) { + var message = "the process exited with exit code $code\n"; + print(message); + // _connector.write(Uint8List.fromList(message.codeUnits)); + onClose(message); + if (code == 0 || code == 1) { + getIt().add(HomeTabEvent.remove(this)); + } + }); + } +} + +bool get isDesktop { + if (kIsWeb) return false; + return [ + TargetPlatform.windows, + TargetPlatform.linux, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); +} + +class TerminalPanel extends StatefulWidget { + final TerminalTab _tab; + + const TerminalPanel(TerminalTab tab, {Key? key}) + : _tab = tab, + super(key: key); + + @override + State createState() => _TtyPanelState(); +} + +class _TtyPanelState extends State + with AutomaticKeepAliveClientMixin, ProfilesPop { + final terminal = Terminal( + maxLines: 10000, + platform: TerminalTargetPlatform.windows, + ); + + final terminalController = TerminalController(); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.endOfFrame.then( + (_) { + if (mounted) _init(); + }, + ); + } + + Future _init() async { + developer.log("_TtyPanelState._init"); + await widget._tab._init((message) { + terminal.write(message); + }); + var connector = widget._tab._connector; + + terminal.onIconChange = (path) async {}; + + terminal.onTitleChange = (title) { + widget._tab.title.value = Text(title); + }; + terminal.onResize = (w, h, pw, ph) { + connector.resize(h, w, pw, pw); + }; + _bindZModelHandle(connector.input, connector.output); + } + + _bindZModelHandle(StreamSink stdin, Stream stdout) { + final mux = ZModemMux( + stdin: stdin, + stdout: stdout, + ); + mux.onTerminalInput = terminal.write; + mux.onFileOffer = _handleFileOffer; + mux.onFileRequest = _handleFileRequest; + terminal.onOutput = mux.terminalWrite; + } + + void _handleFileOffer(ZModemOffer offer) async { + final outputDir = await FilePicker.platform.getDirectoryPath(); + if (outputDir == null) { + offer.skip(); + return; + } + final file = File(path.join(outputDir, offer.info.pathname)); + + void updateProgress(int received) { + final length = offer.info.length; + if (length != null) { + terminal.write('\r'); + terminal.write('\x1b[K'); + terminal.write('${offer.info.pathname}: '); + terminal.write((received / length * 100.0).toStringAsFixed(1)); + terminal.write('%'); + } + } + + await offer + .accept(0) + .cast>() + .transform(WithProgress(onProgress: updateProgress)) + .pipe(file.openWrite()); + + terminal.write('\r\n'); + terminal.write(SS.of(context).received_file(offer.info.pathname)); + } + + Future> _handleFileRequest() async { + final result = await FilePicker.platform.pickFiles(withReadStream: true); + + if (result == null) { + return []; + } + + void updateProgress(PlatformFile file, int received) { + terminal.write('\r'); + terminal.write('\x1b[K'); + terminal.write('${file.name}: '); + terminal.write((received / file.size * 100).toStringAsFixed(1)); + terminal.write('%'); + } + + return result.files.map( + (file) => ZModemCallbackOffer( + ZModemFileInfo( + pathname: path.basename(file.path!), + length: file.size, + mode: '100644', + filesRemaining: 1, + bytesRemaining: file.size, + ), + onAccept: (offset) => file.readStream! + .skip(offset) + .transform( + WithProgress(onProgress: (bytes) => updateProgress(file, bytes)), + ) + .cast(), + onSkip: () { + terminal.write('\r\n'); + terminal.write('Rejected ${file.name}'); + }, + ), + ); + } + + @override + void dispose() { + widget._tab._connector.dispose(); + super.dispose(); + } + + Widget _buildNativeMenu(Widget child) { + return ContextMenuRegion( + onDismissed: () => setState(() => ""), + onItemSelected: (item) async { + print(item.action); + if (item.action == "copy") { + final selection = terminalController.selection; + if (selection != null) { + final text = terminal.buffer.getText(selection); + terminalController.clearSelection(); + await Clipboard.setData(ClipboardData(text: text)); + EasyLoading.showSuccess("复制成功"); + } + } else if (item.action == "paste") { + final data = await Clipboard.getData('text/plain'); + final text = data?.text; + if (text != null) { + terminal.paste(text); + } + } else if (item.action == "new") { + var connector = LocalConnector(); + TabItem item = TerminalTab( + connector.executable, + connector, + icon: connector.icon, + ); + getIt().add(HomeTabEvent.add(item)); + } + }, + menuItems: [ + MenuItem(title: SS.of(context).copy, action: "copy"), + MenuItem(title: SS.of(context).paste, action: "paste"), + MenuItem( + title: SS.of(context).new_tab, + action: "new", + ), + ], + child: child, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return _buildNativeMenu( + //Tomorrow + BlocBuilder( + buildWhen: (p, c) => (p.colorSchemes != c.colorSchemes || + p.currentColorName != c.currentColorName), + builder: (context, state) { + return TerminalView( + textStyle: const TerminalStyle( + fontFamily: "Meslo LG L DZ for Powerline", + ), + terminal, + padding: const EdgeInsets.all(5), + controller: terminalController, + theme: state.currentColor, + autofocus: true, + // onSecondaryTapDown: (details, offset) async { + // final selection = terminalController.selection; + // if (selection != null) { + // final text = terminal.buffer.getText(selection); + // terminalController.clearSelection(); + // await Clipboard.setData(ClipboardData(text: text)); + // } else { + // final data = await Clipboard.getData('text/plain'); + // final text = data?.text; + // if (text != null) { + // terminal.paste(text); + // } + // } + // }, + ); + }, + ), + ); + } + + @override + bool get wantKeepAlive => true; +} + +String get shell { + if (Platform.isMacOS || Platform.isLinux) { + return Platform.environment['SHELL'] ?? 'bash'; + } + + if (Platform.isWindows) { + if (Process.runSync("where", ["pwsh.exe"]).exitCode == 0) { + return 'pwsh.exe'; + } + return 'powershell.exe'; + // return 'cmd.exe'; + } + + return 'sh'; +} + +class WithProgress extends StreamTransformerBase, List> { + WithProgress({this.onProgress}); + + void Function(int progress)? onProgress; + + var _progress = 0; + + int get progress => _progress; + + @override + Stream> bind(Stream> stream) { + return stream.transform(StreamTransformer, List>.fromHandlers( + handleData: (List data, EventSink> sink) { + _progress += data.length; + onProgress?.call(_progress); + sink.add(data); + }, + )); + } +} diff --git a/lib/ui/theme/app_theme.dart b/lib/ui/theme/app_theme.dart new file mode 100644 index 0000000..585fe19 --- /dev/null +++ b/lib/ui/theme/app_theme.dart @@ -0,0 +1,79 @@ +import 'package:fluent_ui/fluent_ui.dart' show ColorExtension; +import 'package:flutter/material.dart'; +import 'package:fterm/gen/fonts.gen.dart'; +import 'package:xterm/xterm.dart'; + + +@immutable +class AppTheme extends ThemeExtension { + final Duration animationDuration; + final Curve animationCurve; + final Duration fastAnimationDuration; + + const AppTheme( + {required this.animationDuration, + required this.animationCurve, + required this.fastAnimationDuration}); + + @override + ThemeExtension copyWith() { + return AppTheme( + animationDuration: animationDuration, + animationCurve: animationCurve, + fastAnimationDuration: fastAnimationDuration, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, double t) { + if (other is! AppTheme) { + return this; + } + return AppTheme( + animationDuration: animationDuration, + animationCurve: animationCurve, + fastAnimationDuration: fastAnimationDuration, + ); + } +} + +mixin AppThemeData { + ThemeData materialTheme(BuildContext context, TerminalTheme colors) { + var colorScheme = ColorScheme.fromSeed( + brightness: Brightness.dark, + seedColor: colors.background, + background: colors.background, + ); + final bool isDark = colorScheme.brightness == Brightness.dark; + + // For surfaces that use primary color in light themes and surface color in dark + final Color primarySurfaceColor = + isDark ? colorScheme.surface : colorScheme.primary; + final Color onPrimarySurfaceColor = + isDark ? colorScheme.onSurface : colorScheme.onPrimary; + return ThemeData( + brightness: Brightness.dark, + colorScheme: colorScheme, + useMaterial3: true, + indicatorColor: onPrimarySurfaceColor, + primaryColor: primarySurfaceColor, + fontFamily: FontFamily.mesloLGLForPowerline, + ).copyWith( + cardColor: colors.background, + appBarTheme: Theme.of(context).appBarTheme.copyWith( + backgroundColor: colors.background.toAccentColor().dark, + foregroundColor: colors.foreground, + ), + hintColor: colors.foreground.withAlpha(100), + textTheme: Theme.of(context).textTheme.apply( + bodyColor: colors.foreground, + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: colors.foreground, + ), + ), + ); + } +} diff --git a/lib/ui/widget/radio.dart b/lib/ui/widget/radio.dart new file mode 100644 index 0000000..c194db9 --- /dev/null +++ b/lib/ui/widget/radio.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; + +class RadioFormGroup extends FormField { + RadioFormGroup( + T groupValue, { + required List items, + super.key, + super.onSaved, + Function(T? value)? onChanged, + }) : super( + initialValue: groupValue, + builder: (FormFieldState field) { + return RadioGroup(field.value, items: items, onChanged: (v) { + field.didChange(v); + onChanged?.call(v); + }); + }, + ); +} + +class RadioGroup extends StatelessWidget { + final List items; + final Function(T? value)? onChanged; + final T groupValue; + + const RadioGroup(this.groupValue, + {Key? key, required this.items, this.onChanged}) + : super(key: key); + + @override + Widget build(BuildContext context) { + var selectColor = Theme.of(context).secondaryHeaderColor; + var color = Colors.transparent; + return Row( + children: [ + ...items.mapIndexed( + (i, e) { + var widget = Container( + padding: e.padding ?? + const EdgeInsets.symmetric(vertical: 3, horizontal: 15), + child: e, + ); + var card = Card( + margin: EdgeInsets.zero, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.zero, + ), + ), + color: groupValue == e.value ? selectColor : color, + child: widget, + ); + if (i == 0) { + card = Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all( + Radius.circular(8.0), + ).copyWith( + topRight: Radius.zero, + bottomRight: Radius.zero, + ), + ), + color: groupValue == e.value ? selectColor : color, + child: widget, + ); + } else if (i == items.length - 1) { + card = Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all( + Radius.circular(8.0), + ).copyWith( + topLeft: Radius.zero, + bottomLeft: Radius.zero, + ), + ), + color: groupValue == e.value ? selectColor : color, + child: widget, + ); + } + return GestureDetector( + onTap: () { + onChanged?.call(e.value); + }, + child: card, + ); + }, + ), + ], + ); + } +} + +class RadioItem extends StatelessWidget { + final Widget title; + final T value; + final EdgeInsetsGeometry? padding; + + const RadioItem(this.value, {Key? key, required this.title, this.padding}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return title; + } +} diff --git a/lib/ui/windows/drag_to_move_area.dart b/lib/ui/windows/drag_to_move_area.dart new file mode 100644 index 0000000..d8e65c4 --- /dev/null +++ b/lib/ui/windows/drag_to_move_area.dart @@ -0,0 +1,25 @@ +import 'package:bitsdojo_window/bitsdojo_window.dart'; +import 'package:flutter/material.dart'; + +class DragToMoveArea extends StatelessWidget { + const DragToMoveArea({ + Key? key, + required this.child, + }) : super(key: key); + + final Widget child; + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onPanStart: (details) { + appWindow.startDragging(); + }, + onDoubleTap: () async { + appWindow.maximizeOrRestore(); + }, + child: child, + ); + } +} diff --git a/lib/ui/windows/draggeble_bar.dart b/lib/ui/windows/draggeble_bar.dart new file mode 100644 index 0000000..98a84d4 --- /dev/null +++ b/lib/ui/windows/draggeble_bar.dart @@ -0,0 +1,29 @@ + +import 'package:flutter/material.dart'; + +import 'drag_to_move_area.dart'; + +class DraggebleAppBar extends StatelessWidget implements PreferredSizeWidget { + final Brightness brightness; + + const DraggebleAppBar({ + super.key, + required this.brightness, + }); + + @override + Widget build(BuildContext context) { + //0xff1C1C1C + return DragToMoveArea( + child: Container( + height: kToolbarHeight / 1.4, +/* child: Platform.isWindows?WindowCaption( + brightness: brightness, + ):null,*/ + ), + ); + + } + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/lib/ui/windows/window_caption.dart b/lib/ui/windows/window_caption.dart new file mode 100644 index 0000000..dd78053 --- /dev/null +++ b/lib/ui/windows/window_caption.dart @@ -0,0 +1,126 @@ +import 'package:bitsdojo_window/bitsdojo_window.dart'; +import 'package:flutter/material.dart'; +import 'package:fterm/ui/windows/window_caption_button.dart'; + + + +import 'drag_to_move_area.dart'; + +const double kWindowCaptionHeight = 32; + +/// A widget to simulate the title bar of windows 11. +/// +/// {@tool snippet} +/// +/// ```dart +/// Scaffold( +/// appBar: PreferredSize( +/// child: WindowCaption( +/// brightness: Theme.of(context).brightness, +/// title: Text('window_manager_example'), +/// ), +/// preferredSize: const Size.fromHeight(kWindowCaptionHeight), +/// ), +/// ) +/// ``` +/// {@end-tool} +class WindowCaption extends StatefulWidget { + const WindowCaption({ + Key? key, + this.title, + this.backgroundColor, + this.brightness, + }) : super(key: key); + + final Widget? title; + final Color? backgroundColor; + final Brightness? brightness; + + @override + State createState() => _WindowCaptionState(); +} + +class _WindowCaptionState extends State { + + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: widget.backgroundColor ?? + (widget.brightness == Brightness.dark + ? const Color(0xff1C1C1C) + : Colors.transparent), + ), + child: Row( + children: [ + Expanded( + child: DragToMoveArea( + child: SizedBox( + height: double.infinity, + child: Row( + children: [ + Container( + padding: const EdgeInsets.only(left: 16), + child: DefaultTextStyle( + style: TextStyle( + color: widget.brightness == Brightness.light + ? Colors.black.withOpacity(0.8956) + : Colors.white, + fontSize: 14, + ), + child: widget.title ?? Container(), + ), + ), + ], + ), + ), + ), + ), + WindowCaptionButton.minimize( + brightness: widget.brightness, + onPressed: () async { + bool isMinimized = !appWindow.isVisible; + if (isMinimized) { + appWindow.restore(); + } else { + appWindow.minimize(); + } + }, + ), + appWindow.isMaximized?WindowCaptionButton.unmaximize( + brightness: widget.brightness, + onPressed: () { + setState(() { + appWindow.restore(); + }); + }, + ):WindowCaptionButton.maximize( + brightness: widget.brightness, + onPressed: () { + setState(() { + appWindow.maximize(); + }); + }, + ), + WindowCaptionButton.close( + brightness: widget.brightness, + onPressed: () { + appWindow.close(); + }, + ), + ], + ), + ); + } + + @override + void onWindowMaximize() { + setState(() {}); + } + + @override + void onWindowUnmaximize() { + setState(() {}); + } +} diff --git a/lib/ui/windows/window_caption_button.dart b/lib/ui/windows/window_caption_button.dart new file mode 100644 index 0000000..5ad3e01 --- /dev/null +++ b/lib/ui/windows/window_caption_button.dart @@ -0,0 +1,206 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/material.dart'; + +import '../../gen/assets.gen.dart'; + +class WindowCaptionButtonIcon extends StatelessWidget { + const WindowCaptionButtonIcon({ + Key? key, + required this.name, + this.color, + }) : super(key: key); + + final String name; + final Color? color; + + @override + Widget build(BuildContext context) { + return Image.asset( + name, + width: 15, + color: color, + filterQuality: FilterQuality.high, + ); + } +} + +// ignore: must_be_immutable +class WindowCaptionButton extends StatefulWidget { + WindowCaptionButton({ + Key? key, + this.brightness, + this.icon, + this.iconName, + required this.onPressed, + }) : super(key: key); + WindowCaptionButton.close({ + Key? key, + this.brightness, + this.icon, + this.onPressed, + }) : iconName = Assets.images.icChromeClose.path, + _lightButtonBgColorScheme = _ButtonBgColorScheme( + normal: Colors.transparent, + hovered: const Color(0xffC42B1C), + pressed: const Color(0xffC42B1C).withOpacity(0.9), + ), + _lightButtonIconColorScheme = _ButtonIconColorScheme( + normal: Colors.black.withOpacity(0.8956), + hovered: Colors.white, + pressed: Colors.white.withOpacity(0.7), + disabled: Colors.black.withOpacity(0.3614), + ), + _darkButtonBgColorScheme = _ButtonBgColorScheme( + normal: Colors.transparent, + hovered: const Color(0xffC42B1C), + pressed: const Color(0xffC42B1C).withOpacity(0.9), + ), + _darkButtonIconColorScheme = _ButtonIconColorScheme( + normal: Colors.white, + hovered: Colors.white, + pressed: Colors.white.withOpacity(0.786), + disabled: Colors.black.withOpacity(0.3628), + ), + super(key: key); + + WindowCaptionButton.unmaximize({ + Key? key, + this.brightness, + this.icon, + this.onPressed, + }) : iconName = Assets.images.icChromeUnmaximize.path, + super(key: key); + + WindowCaptionButton.maximize({ + Key? key, + this.brightness, + this.icon, + this.onPressed, + }) : iconName = Assets.images.icChromeMaximize.path, + super(key: key); + + WindowCaptionButton.minimize({ + Key? key, + this.brightness, + this.icon, + this.onPressed, + }) : iconName = Assets.images.icChromeMinimize.path, + super(key: key); + + final Brightness? brightness; + final Widget? icon; + final String? iconName; + final VoidCallback? onPressed; + + _ButtonBgColorScheme _lightButtonBgColorScheme = _ButtonBgColorScheme( + normal: Colors.transparent, + hovered: Colors.black.withOpacity(0.0373), + pressed: Colors.black.withOpacity(0.0241), + ); + _ButtonIconColorScheme _lightButtonIconColorScheme = _ButtonIconColorScheme( + normal: Colors.black.withOpacity(0.8956), + hovered: Colors.black.withOpacity(0.8956), + pressed: Colors.black.withOpacity(0.6063), + disabled: Colors.black.withOpacity(0.3614), + ); + _ButtonBgColorScheme _darkButtonBgColorScheme = _ButtonBgColorScheme( + normal: Colors.transparent, + hovered: Colors.white.withOpacity(0.0605), + pressed: Colors.white.withOpacity(0.0419), + ); + _ButtonIconColorScheme _darkButtonIconColorScheme = _ButtonIconColorScheme( + normal: Colors.white, + hovered: Colors.white, + pressed: Colors.white.withOpacity(0.786), + disabled: Colors.black.withOpacity(0.3628), + ); + + _ButtonBgColorScheme get buttonBgColorScheme => brightness != Brightness.dark + ? _lightButtonBgColorScheme + : _darkButtonBgColorScheme; + + _ButtonIconColorScheme get buttonIconColorScheme => + brightness != Brightness.dark + ? _lightButtonIconColorScheme + : _darkButtonIconColorScheme; + + @override + State createState() => _WindowCaptionButtonState(); +} + +class _WindowCaptionButtonState extends State { + bool _isHovering = false; + bool _isPressed = false; + + void _onEntered({required bool hovered}) { + setState(() => _isHovering = hovered); + } + + void _onActive({required bool pressed}) { + setState(() => _isPressed = pressed); + } + + @override + Widget build(BuildContext context) { + Color bgColor = widget.buttonBgColorScheme.normal; + Color iconColor = widget.buttonIconColorScheme.normal; + + if (_isHovering) { + bgColor = widget.buttonBgColorScheme.hovered; + iconColor = widget.buttonIconColorScheme.hovered; + } + if (_isPressed) { + bgColor = widget.buttonBgColorScheme.pressed; + iconColor = widget.buttonIconColorScheme.pressed; + } + + return MouseRegion( + onExit: (value) => _onEntered(hovered: false), + onHover: (value) => _onEntered(hovered: true), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: (_) => _onActive(pressed: true), + onTapCancel: () => _onActive(pressed: false), + onTapUp: (_) => _onActive(pressed: false), + onTap: widget.onPressed, + child: Container( + constraints: const BoxConstraints(minWidth: 46, minHeight: 32), + decoration: BoxDecoration( + color: bgColor, + ), + child: Center( + child: WindowCaptionButtonIcon( + name: widget.iconName!, + color: iconColor, + ), + ), + ), + ), + ); + } +} + +class _ButtonBgColorScheme { + _ButtonBgColorScheme({ + required this.normal, + required this.hovered, + required this.pressed, + }); + final Color normal; + final Color hovered; + final Color pressed; +} + +class _ButtonIconColorScheme { + _ButtonIconColorScheme({ + required this.normal, + required this.hovered, + required this.pressed, + required this.disabled, + }); + final Color normal; + final Color hovered; + final Color pressed; + final Color disabled; +} diff --git a/lib/utils/string_ext.dart b/lib/utils/string_ext.dart new file mode 100644 index 0000000..c797549 --- /dev/null +++ b/lib/utils/string_ext.dart @@ -0,0 +1,8 @@ +import 'dart:ui'; + +extension StringLocale on String { + Locale toLocale() { + var array = split("_"); + return Locale(array[0], array[1]); + } +} diff --git a/lib/utils/target_platform.dart b/lib/utils/target_platform.dart new file mode 100644 index 0000000..992bccc --- /dev/null +++ b/lib/utils/target_platform.dart @@ -0,0 +1,11 @@ +import 'package:flutter/widgets.dart'; + +extension TargetPlatformExtension on TargetPlatform { + bool get isApple => + this == TargetPlatform.iOS || this == TargetPlatform.macOS; + + bool get isDesktop => + this == TargetPlatform.linux || + this == TargetPlatform.macOS || + this == TargetPlatform.windows; +} diff --git a/linux/.gitignore b/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 0000000..b908515 --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "fterm") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.fterm") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..0832883 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,27 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); + bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) native_context_menu_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "NativeContextMenuPlugin"); + native_context_menu_plugin_register_with_registrar(native_context_menu_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..84061f0 --- /dev/null +++ b/linux/flutter/generated_plugins.cmake @@ -0,0 +1,28 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + bitsdojo_window_linux + flutter_secure_storage_linux + native_context_menu + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_pty +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/main.cc b/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/my_application.cc b/linux/my_application.cc new file mode 100644 index 0000000..c902489 --- /dev/null +++ b/linux/my_application.cc @@ -0,0 +1,110 @@ +#include "my_application.h" +#include +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "fterm"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "fterm"); + } + +// gtk_window_set_default_size(window, 1280, 720); +// gtk_widget_show(GTK_WIDGET(window)); + + + auto bdw = bitsdojo_window_from(window); // <--- add this line + bdw->setCustomFrame(true); // <-- add this line + //gtk_window_set_default_size(window, 1280, 720); // <-- comment this line + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/linux/my_application.h b/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/macos/.gitignore b/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..3a6d842 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,22 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import bitsdojo_window_macos +import flutter_secure_storage_macos +import native_context_menu +import path_provider_foundation +import shared_preferences_foundation +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + NativeContextMenuPlugin.register(with: registry.registrar(forPlugin: "NativeContextMenuPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..049abe2 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.14' + +# 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', 'ephemeral', '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 Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 0000000..55ac357 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,60 @@ +PODS: + - bitsdojo_window_macos (0.0.1): + - FlutterMacOS + - flutter_pty (0.0.1): + - FlutterMacOS + - flutter_secure_storage_macos (6.1.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - native_context_menu (0.0.1): + - FlutterMacOS + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`) + - flutter_pty (from `Flutter/ephemeral/.symlinks/plugins/flutter_pty/macos`) + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - native_context_menu (from `Flutter/ephemeral/.symlinks/plugins/native_context_menu/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +EXTERNAL SOURCES: + bitsdojo_window_macos: + :path: Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos + flutter_pty: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_pty/macos + flutter_secure_storage_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos + FlutterMacOS: + :path: Flutter/ephemeral + native_context_menu: + :path: Flutter/ephemeral/.symlinks/plugins/native_context_menu/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00 + flutter_pty: 41b6f848ade294be726a6b94cdd4a67c3bc52f59 + flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + native_context_menu: 8b710e17c5962cf3f005b805eb97cce668b3839a + path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 + shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c + url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 + +PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 + +COCOAPODS: 1.12.0 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6732da0 --- /dev/null +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,640 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + C0B7B1479427EF88454A7C4F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4041134B448E510119E261CA /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* fterm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fterm.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 363E699F82C31C2D60EAE547 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 4041134B448E510119E261CA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + DB9BFD6AB5CD76AD19E4233D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + E6E6CE68EDA954B3DA861DC6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C0B7B1479427EF88454A7C4F /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + FC412D22B1CC528859D1D777 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* fterm.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4041134B448E510119E261CA /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + FC412D22B1CC528859D1D777 /* Pods */ = { + isa = PBXGroup; + children = ( + E6E6CE68EDA954B3DA861DC6 /* Pods-Runner.debug.xcconfig */, + DB9BFD6AB5CD76AD19E4233D /* Pods-Runner.release.xcconfig */, + 363E699F82C31C2D60EAE547 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9A8F0BA46FCB5D49BB6CB474 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 243FBDAFA422EA6EFB593E30 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* fterm.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 243FBDAFA422EA6EFB593E30 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 9A8F0BA46FCB5D49BB6CB474 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = P76CHDQL86; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.github.springeye.fterm; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = P76CHDQL86; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.github.springeye.fterm; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = P76CHDQL86; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.github.springeye.fterm; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..394b282 --- /dev/null +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..d53ef64 --- /dev/null +++ b/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..96d3fee --- /dev/null +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "info": { + "version": 1, + "author": "xcode" + }, + "images": [ + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_16.png", + "scale": "1x" + }, + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "2x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "1x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_64.png", + "scale": "2x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_128.png", + "scale": "1x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "2x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "1x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "2x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "1x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_1024.png", + "scale": "2x" + } + ] +} \ No newline at end of file diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..e0d74eb Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..6724d5d Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..8cb38eb Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..5ffb709 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..ee151ce Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..77ae8ab Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..132d2af Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..a2b21cd --- /dev/null +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = fterm + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.fterm + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..cb383e9 --- /dev/null +++ b/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + keychain-access-groups + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..69cfbba --- /dev/null +++ b/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,18 @@ +import Cocoa +import FlutterMacOS +import bitsdojo_window_macos // Add this line +class MainFlutterWindow: BitsdojoWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } + override func bitsdojo_window_configure() -> UInt { + return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements new file mode 100644 index 0000000..fbad023 --- /dev/null +++ b/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + keychain-access-groups + + + diff --git a/macos/packaging/dmg/make_config.yaml b/macos/packaging/dmg/make_config.yaml new file mode 100644 index 0000000..11d6cb1 --- /dev/null +++ b/macos/packaging/dmg/make_config.yaml @@ -0,0 +1,10 @@ +title: fterm +contents: + - x: 448 + y: 344 + type: link + path: "/Applications" + - x: 192 + y: 344 + type: file + path: fterm.app diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..d76b5ec --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1407 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + archive: + dependency: transitive + description: + name: archive + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + url: "https://pub.dev" + source: hosted + version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a + url: "https://pub.dev" + source: hosted + version: "2.4.1" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + bitsdojo_window: + dependency: "direct main" + description: + name: bitsdojo_window + sha256: "1118bc1cd16e6f358431ca4473af57cc1b287d2ceab46dfab6d59a9463160622" + url: "https://pub.dev" + source: hosted + version: "0.1.5" + bitsdojo_window_linux: + dependency: transitive + description: + name: bitsdojo_window_linux + sha256: d3804a30315fcbb43b28acc86d1180ce0be22c0c738ad2da9e5ade4d8dbd9655 + url: "https://pub.dev" + source: hosted + version: "0.1.3" + bitsdojo_window_macos: + dependency: transitive + description: + name: bitsdojo_window_macos + sha256: d2a9886c74516c5b84c1dd65ab8ee5d1c52055b265ebf0e7d664dee28366b521 + url: "https://pub.dev" + source: hosted + version: "0.1.3" + bitsdojo_window_platform_interface: + dependency: transitive + description: + name: bitsdojo_window_platform_interface + sha256: "65daa015a0c6dba749bdd35a0f092e7a8ba8b0766aa0480eb3ef808086f6e27c" + url: "https://pub.dev" + source: hosted + version: "0.1.2" + bitsdojo_window_windows: + dependency: transitive + description: + name: bitsdojo_window_windows + sha256: "8766a40aac84a6d7bdcaa716b24997e028fc9a9a1800495fc031721fd5a22ed0" + url: "https://pub.dev" + source: hosted + version: "0.1.5" + bloc: + dependency: transitive + description: + name: bloc + sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + url: "https://pub.dev" + source: hosted + version: "8.1.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e" + url: "https://pub.dev" + source: hosted + version: "7.2.9" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452" + url: "https://pub.dev" + source: hosted + version: "8.6.0" + change_app_package_name: + dependency: "direct dev" + description: + name: change_app_package_name + sha256: f9ebaf68a4b5a68c581492579bb68273c523ef325fbf9ce2f1b57fb136ad023b + url: "https://pub.dev" + source: hosted + version: "1.1.0" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" + colorize: + dependency: transitive + description: + name: colorize + sha256: "584746cd6ba1cba0633b6720f494fe6f9601c4170f0666c1579d2aa2a61071ba" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + console: + dependency: transitive + description: + name: console + sha256: e04e7824384c5b39389acdd6dc7d33f3efe6b232f6f16d7626f194f6a01ad69a + url: "https://pub.dev" + source: hosted + version: "4.1.0" + context_menus: + dependency: "direct main" + description: + name: context_menus + sha256: "25313f2a17dc936f541f8012761648cb58d936c5d6f6bf7282f137a4b9dedddb" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad + url: "https://pub.dev" + source: hosted + version: "2.3.1" + dartssh2: + dependency: "direct main" + description: + name: dartssh2 + sha256: "48d35ad9b697627b59f9ebeab4e4936266dc153cff96f02c997d3fe30df4d80a" + url: "https://pub.dev" + source: hosted + version: "2.9.1-pre" + dartx: + dependency: transitive + description: + name: dartx + sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + dio: + dependency: transitive + description: + name: dio + sha256: "347d56c26d63519552ef9a569f2a593dda99a81fdbdff13c584b7197cfe05059" + url: "https://pub.dev" + source: hosted + version: "5.1.2" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + ffigen: + dependency: "direct dev" + description: + name: ffigen + sha256: d3e76c2ad48a4e7f93a29a162006f00eba46ce7c08194a77bb5c5e97d1b5ff0a + url: "https://pub.dev" + source: hosted + version: "8.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: b85eb92b175767fdaa0c543bf3b0d1f610fe966412ea72845fe5ba7801e763ff + url: "https://pub.dev" + source: hosted + version: "5.2.10" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + fluent_ui: + dependency: "direct main" + description: + name: fluent_ui + sha256: "860606280da3b5d49920c36a0aee7b456c1a1c01e67c907184c409ccb4153b34" + url: "https://pub.dev" + source: hosted + version: "4.6.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + url: "https://pub.dev" + source: hosted + version: "8.1.3" + flutter_easyloading: + dependency: "direct main" + description: + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c + url: "https://pub.dev" + source: hosted + version: "3.0.5" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: e8637dd6a59860f89e5e71be0a27101ec32dad1a0ed7fd879fd23b6e91d5004d + url: "https://pub.dev" + source: hosted + version: "5.3.1" + flutter_gen_runner: + dependency: "direct dev" + description: + name: flutter_gen_runner + sha256: "7de1bf4fc0439be0fef3178b6423d5c7f1f9f3a38a7c6fafe75d7f70ff4856d7" + url: "https://pub.dev" + source: hosted + version: "5.3.1" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + flutter_pty: + dependency: "direct main" + description: + name: flutter_pty + sha256: "08b6f37a4f394159e3a6adb6f07295e6fb6acb71270c87a4d0be187db34535cd" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: "36e11b79ac7011d9203313468c5827fe1215b0fa03df384cfe2891a68ed74ed5" + url: "https://pub.dev" + source: hosted + version: "1.75.3" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + url: "https://pub.dev" + source: hosted + version: "8.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_spinkit: + dependency: transitive + description: + name: flutter_spinkit + sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + url: "https://pub.dev" + source: hosted + version: "5.2.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "2edb9ef971d0f803860ecd9084afd48c717d002141ad77b69be3e976bee7190e" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: "529de303c739fca98cd7ece5fca500d8ff89649f1bb4b4e94fb20954abcd7468" + url: "https://pub.dev" + source: hosted + version: "7.6.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "00d1b67d6e9fa443331da229084dd3eb04407f5a2dff22940bd7bba6af5722c3" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + graphs: + dependency: transitive + description: + name: graphs + sha256: "772db3d53d23361d4ffcf5a9bb091cf3ee9b22f2be52cd107cd7a2683a89ba0e" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + hive: + dependency: "direct main" + description: + name: hive + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + hive_flutter: + dependency: "direct main" + description: + name: hive_flutter + sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc + url: "https://pub.dev" + source: hosted + version: "1.1.0" + hive_generator: + dependency: "direct dev" + description: + name: hive_generator + sha256: "65998cc4d2cd9680a3d9709d893d2f6bb15e6c1f92626c3f1fa650b4b3281521" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + http: + dependency: transitive + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf + url: "https://pub.dev" + source: hosted + version: "4.0.17" + injectable: + dependency: "direct main" + description: + name: injectable + sha256: c0cc829eb71c950889e2ae363f0755a9686852b5ea21584b5aefc106bce64d0c + url: "https://pub.dev" + source: hosted + version: "2.1.1" + injectable_generator: + dependency: "direct dev" + description: + name: injectable_generator + sha256: "0670348cfeb5f62de97977f21e11c826c41e4fcf2a34e686de3aa94f1d47a190" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + innosetup: + dependency: "direct dev" + description: + name: innosetup + sha256: "9bc0e1bc3df9c8fbbbc74d801ae1a650cdbe62de72fa0bb13c9f16f6a9e45e83" + url: "https://pub.dev" + source: hosted + version: "0.1.3" + intl: + dependency: "direct main" + description: + name: intl + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + url: "https://pub.dev" + source: hosted + version: "0.18.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: "61a60716544392a82726dd0fa1dd6f5f1fd32aec66422b6e229e7b90d52325c4" + url: "https://pub.dev" + source: hosted + version: "6.7.0" + lints: + dependency: transitive + description: + name: lints + sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + math_expressions: + dependency: transitive + description: + name: math_expressions + sha256: "3576593617c3870d75728a751f6ec6e606706d44e363f088ac394b5a28a98064" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + msix: + dependency: "direct dev" + description: + name: msix + sha256: c4ac0055da46764d9dca51f2f53b488294080fc8dc2de5730866558a37c6c07a + url: "https://pub.dev" + source: hosted + version: "3.14.1" + native_context_menu: + dependency: "direct main" + description: + name: native_context_menu + sha256: "566f13d1f55e57bc8aca3b71b157b1ff03c2cc3821f6e9d980f76233ed30c9b7" + url: "https://pub.dev" + source: hosted + version: "0.2.2+5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.dev" + source: hosted + version: "2.0.27" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" + source: hosted + version: "2.1.11" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + url: "https://pub.dev" + source: hosted + version: "2.1.6" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + pinenacl: + dependency: transitive + description: + name: pinenacl + sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + platform_info: + dependency: transitive + description: + name: platform_info + sha256: "012e73712166cf0b56d3eb95c0d33491f56b428c169eca385f036448474147e4" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + popover: + dependency: "direct main" + description: + name: popover + sha256: "59f4a55ebb484d012c8aaa273ad58eee571945231b71fb938c5a69f63b5a94d4" + url: "https://pub.dev" + source: hosted + version: "0.2.8+2" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + provider: + dependency: transitive + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + puppeteer: + dependency: transitive + description: + name: puppeteer + sha256: dd49117259867d0ce0de33ddd95628fb70cff94581a6432c08272447b8dd1d27 + url: "https://pub.dev" + source: hosted + version: "2.24.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + scroll_pos: + dependency: "direct main" + description: + name: scroll_pos + sha256: "4246bff3afc779d87cdf650a67d42d67ae71b23ff020d14592e6b89e28a7f9cc" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + settings_ui: + dependency: "direct main" + description: + name: settings_ui + sha256: d9838037cb554b24b4218b2d07666fbada3478882edefae375ee892b6c820ef3 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33" + url: "https://pub.dev" + source: hosted + version: "1.3.2" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + statsfl: + dependency: "direct main" + description: + name: statsfl + sha256: "12901533eee23cc04f01858f1e6851beec27d927a9afa694bb3d68403a5e0d13" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + time: + dependency: transitive + description: + name: time + sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + url: "https://pub.dev" + source: hosted + version: "6.1.11" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "1a5848f598acc5b7d8f7c18b8cb834ab667e59a13edc3c93e9d09cf38cc6bc87" + url: "https://pub.dev" + source: hosted + version: "6.0.34" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab" + url: "https://pub.dev" + source: hosted + version: "2.0.17" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f + url: "https://pub.dev" + source: hosted + version: "1.1.6" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + version: + dependency: "direct dev" + description: + name: version + sha256: "3d4140128e6ea10d83da32fef2fa4003fccbf6852217bb854845802f04191f94" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webdav_client: + dependency: "direct main" + description: + name: webdav_client + sha256: b3f5afee27e7db5635817ddd79d57f56d43fdc6dad4c6bc93b0703261f96064c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + win32: + dependency: transitive + description: + name: win32 + sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + url: "https://pub.dev" + source: hosted + version: "3.1.4" + win32_registry: + dependency: "direct main" + description: + name: win32_registry + sha256: "66e78552f17501aced68fe77425b13156998f1bd3d58f1cd8cd0af2dbe4520e3" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + xterm: + dependency: "direct main" + description: + name: xterm + sha256: "6a02b15d03152b8186e12790902ff28c8a932fc441e89fa7255a7491661a8e69" + url: "https://pub.dev" + source: hosted + version: "3.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + yaml_edit: + dependency: transitive + description: + name: yaml_edit + sha256: "1579d4a0340a83cf9e4d580ea51a16329c916973bffd5bd4b45e911b25d46bfd" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + zmodem: + dependency: "direct main" + description: + name: zmodem + sha256: "3b7e5b29f3a7d8aee472029b05165a68438eff2f3f7766edf13daba1e297adbf" + url: "https://pub.dev" + source: hosted + version: "0.0.6" +sdks: + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..4116549 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,165 @@ +name: fterm +description: A new Flutter project. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: +# sdk: '>=2.19.4 <3.0.0' + sdk: '>=3.0.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + fluent_ui: ^4.5.1 + xterm: ^3.4.1 + flutter_pty: ^0.4.0 + dartssh2: ^2.8.2 + flutter_bloc: ^8.1.2 + freezed_annotation: ^2.2.0 + json_annotation: ^4.8.0 + uuid: ^3.0.7 + get_it: ^7.6.0 + context_menus: ^1.0.2 + path_provider: ^2.0.15 + injectable: ^2.1.1 + scroll_pos: ^0.4.0 + flutter_easyloading: ^3.0.5 + ffi: ^2.0.2 + flutter_rust_bridge: ^1.75.3 + bitsdojo_window: ^0.1.5 + popover: ^0.2.8+2 + native_context_menu: ^0.2.2+5 + zmodem: ^0.0.6 + file_picker: ^5.2.10 + statsfl: ^2.3.0 + settings_ui: ^2.0.2 + shared_preferences: ^2.1.1 + flutter_localizations: + sdk: flutter + intl: ^0.18.0 + flutter_svg: ^2.0.6 + win32_registry: ^1.0.2 + go_router: ^7.1.1 + collection: ^1.17.1 + hive: ^2.2.3 + hive_flutter: ^1.1.0 + flutter_secure_storage: ^8.0.0 + webdav_client: ^1.2.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + build_runner: ^2.3.3 + freezed: ^2.3.2 + json_serializable: ^6.6.1 + injectable_generator: ^2.1.5 + innosetup: ^0.1.3 + version: ^3.0.2 + ffigen: ^8.0.2 + flutter_gen_runner: ^5.3.1 + change_app_package_name: ^1.1.0 + flutter_launcher_icons: ^0.13.1 + hive_generator: ^2.0.0 + msix: ^3.14.1 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + generate: true + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + assets: + - assets/colors/schemes/ + - assets/images/ + - assets/icons/ + - assets/terminal.png + - assets/terminal.svg + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + fonts: + - family: Meslo LG L for Powerline + fonts: + - asset: assets/fonts/Meslo_LG_L_Bold_for_Powerline.ttf +# - asset: fonts/Meslo LG L Bold Italic for Powerline.ttf + - asset: assets/fonts/Meslo_LG_L_Italic_for_Powerline.ttf + style: italic +# - asset: fonts/Meslo LG L Regular for Powerline.ttf + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages +# The following section is specific to Flutter. +#dependency_overrides: +# flutter_pty: +# path: ../flutter_pty +flutter_gen: + assets: + exclude: + - assets/colors/schemes/* + # Optional + integrations: + flutter_svg: true +# flare_flutter: true +# rive: true +# lottie: true + + +dependency_overrides: + dartssh2: + version: ^2.9.1-pre diff --git a/resources/fterm1.png b/resources/fterm1.png new file mode 100644 index 0000000..92ee194 Binary files /dev/null and b/resources/fterm1.png differ diff --git a/resources/fterm2.png b/resources/fterm2.png new file mode 100644 index 0000000..acbba8a Binary files /dev/null and b/resources/fterm2.png differ diff --git a/resources/fterm3.png b/resources/fterm3.png new file mode 100644 index 0000000..e6b6b52 Binary files /dev/null and b/resources/fterm3.png differ diff --git a/resources/fterm4.png b/resources/fterm4.png new file mode 100644 index 0000000..89db34e Binary files /dev/null and b/resources/fterm4.png differ diff --git a/resources/fterm5.png b/resources/fterm5.png new file mode 100644 index 0000000..de3130c Binary files /dev/null and b/resources/fterm5.png differ diff --git a/resources/fterm6.png b/resources/fterm6.png new file mode 100644 index 0000000..37167ac Binary files /dev/null and b/resources/fterm6.png differ diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..29ed33a --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,44 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. 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/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:fterm/di/di.dart'; +import 'package:fterm/service/sync_service.dart'; +import 'package:fterm/service/webdav_sync_service.dart'; +import 'package:win32_registry/win32_registry.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + setUpAll(() {}); + + setUp(() {}); + + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + _getWsl(); + }); +} + +void _getWsl() { + const lxssPath = r'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss'; + + final key = Registry.openPath(RegistryHive.currentUser, path: lxssPath); + print('Values:\n'); + for (final value in key.values) { + print(' - ${value.name}==>${value.data}'); + } + print(key.getValueAsString("DefaultDistribution")); + print('\n----------------------------------------' + '----------------------------------------\n'); + + print('Subkeys:\n'); + for (final subkey in key.subkeyNames) { + print(' - $subkey'); + } + key.close(); +} diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 0000000..fd90f8f --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(fterm LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "fterm") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..930d207 --- /dev/null +++ b/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..bac94ba --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + BitsdojoWindowPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + NativeContextMenuPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("NativeContextMenuPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..e65c294 --- /dev/null +++ b/windows/flutter/generated_plugins.cmake @@ -0,0 +1,28 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + bitsdojo_window_windows + flutter_secure_storage_windows + native_context_menu + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_pty +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/windows/packaging/exe/inno_setup.iss b/windows/packaging/exe/inno_setup.iss new file mode 100644 index 0000000..efa12de --- /dev/null +++ b/windows/packaging/exe/inno_setup.iss @@ -0,0 +1,63 @@ +[Setup] + +AppId={{APP_ID}} +AppVersion={{APP_VERSION}} +AppName={{DISPLAY_NAME}} +AppPublisher={{PUBLISHER_NAME}} +AppPublisherURL={{PUBLISHER_URL}} +AppSupportURL={{PUBLISHER_URL}} +AppUpdatesURL={{PUBLISHER_URL}} +DefaultDirName={{INSTALL_DIR_NAME}} +DisableProgramGroupPage=yes +OutputDir=. +OutputBaseFilename={{OUTPUT_BASE_FILENAME}} +Compression=lzma +SolidCompression=yes +SetupIconFile={{SETUP_ICON_FILE}} +WizardStyle=modern +PrivilegesRequired={{PRIVILEGES_REQUIRED}} +ArchitecturesAllowed=x64 +ArchitecturesInstallIn64BitMode=x64 + +[Languages] +{% for locale in LOCALES %} +{% if locale == 'en' %}Name: "english"; MessagesFile: "compiler:Default.isl"{% endif %} +{% if locale == 'hy' %}Name: "armenian"; MessagesFile: "compiler:Languages\\Armenian.isl"{% endif %} +{% if locale == 'bg' %}Name: "bulgarian"; MessagesFile: "compiler:Languages\\Bulgarian.isl"{% endif %} +{% if locale == 'ca' %}Name: "catalan"; MessagesFile: "compiler:Languages\\Catalan.isl"{% endif %} +{% if locale == 'zh' %}Name: "chinesesimplified"; MessagesFile: "compiler:Languages\\ChineseSimplified.isl"{% endif %} +{% if locale == 'co' %}Name: "corsican"; MessagesFile: "compiler:Languages\\Corsican.isl"{% endif %} +{% if locale == 'cs' %}Name: "czech"; MessagesFile: "compiler:Languages\\Czech.isl"{% endif %} +{% if locale == 'da' %}Name: "danish"; MessagesFile: "compiler:Languages\\Danish.isl"{% endif %} +{% if locale == 'nl' %}Name: "dutch"; MessagesFile: "compiler:Languages\\Dutch.isl"{% endif %} +{% if locale == 'fi' %}Name: "finnish"; MessagesFile: "compiler:Languages\\Finnish.isl"{% endif %} +{% if locale == 'fr' %}Name: "french"; MessagesFile: "compiler:Languages\\French.isl"{% endif %} +{% if locale == 'de' %}Name: "german"; MessagesFile: "compiler:Languages\\German.isl"{% endif %} +{% if locale == 'he' %}Name: "hebrew"; MessagesFile: "compiler:Languages\\Hebrew.isl"{% endif %} +{% if locale == 'is' %}Name: "icelandic"; MessagesFile: "compiler:Languages\\Icelandic.isl"{% endif %} +{% if locale == 'it' %}Name: "italian"; MessagesFile: "compiler:Languages\\Italian.isl"{% endif %} +{% if locale == 'ja' %}Name: "japanese"; MessagesFile: "compiler:Languages\\Japanese.isl"{% endif %} +{% if locale == 'no' %}Name: "norwegian"; MessagesFile: "compiler:Languages\\Norwegian.isl"{% endif %} +{% if locale == 'pl' %}Name: "polish"; MessagesFile: "compiler:Languages\\Polish.isl"{% endif %} +{% if locale == 'pt' %}Name: "portuguese"; MessagesFile: "compiler:Languages\\Portuguese.isl"{% endif %} +{% if locale == 'ru' %}Name: "russian"; MessagesFile: "compiler:Languages\\Russian.isl"{% endif %} +{% if locale == 'sk' %}Name: "slovak"; MessagesFile: "compiler:Languages\\Slovak.isl"{% endif %} +{% if locale == 'sl' %}Name: "slovenian"; MessagesFile: "compiler:Languages\\Slovenian.isl"{% endif %} +{% if locale == 'es' %}Name: "spanish"; MessagesFile: "compiler:Languages\\Spanish.isl"{% endif %} +{% if locale == 'tr' %}Name: "turkish"; MessagesFile: "compiler:Languages\\Turkish.isl"{% endif %} +{% if locale == 'uk' %}Name: "ukrainian"; MessagesFile: "compiler:Languages\\Ukrainian.isl"{% endif %} +{% endfor %} + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: {% if CREATE_DESKTOP_ICON != true %}unchecked{% else %}checkedonce{% endif %} +Name: "launchAtStartup"; Description: "{cm:AutoStartProgram,{{DISPLAY_NAME}}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: {% if LAUNCH_AT_STARTUP != true %}unchecked{% else %}checkedonce{% endif %} +[Files] +Source: "{{SOURCE_DIR}}\\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{autoprograms}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}" +Name: "{autodesktop}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}"; Tasks: desktopicon +Name: "{userstartup}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}"; WorkingDir: "{app}"; Tasks: launchAtStartup +[Run] +Filename: "{app}\\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: {% if PRIVILEGES_REQUIRED == 'admin' %}runascurrentuser{% endif %} nowait postinstall skipifsilent \ No newline at end of file diff --git a/windows/packaging/exe/make_config.yaml b/windows/packaging/exe/make_config.yaml new file mode 100644 index 0000000..cecc2d9 --- /dev/null +++ b/windows/packaging/exe/make_config.yaml @@ -0,0 +1,8 @@ +script_template: inno_setup.iss + +app_id: com.github.springeye.fterm +publisher: henjue +publisher_url: https://github.com/springeye/fterm +display_name: fterm +create_desktop_icon: true +install_dir_name: "{userpf}/fterm" \ No newline at end of file diff --git a/windows/packaging/msix/make_config.yaml b/windows/packaging/msix/make_config.yaml new file mode 100644 index 0000000..05542d4 --- /dev/null +++ b/windows/packaging/msix/make_config.yaml @@ -0,0 +1,5 @@ +display_name: fterm +publisher_display_name: henjue +identity_name: com.github.springeye.fterm +msix_version: 0.0.0.1 +logo_path: assets/terminal.png \ No newline at end of file diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc new file mode 100644 index 0000000..5f64b75 --- /dev/null +++ b/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "fterm" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "fterm" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "fterm.exe" "\0" + VALUE "ProductName", "fterm" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..b25e363 --- /dev/null +++ b/windows/runner/flutter_window.cpp @@ -0,0 +1,66 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp new file mode 100644 index 0000000..42edf52 --- /dev/null +++ b/windows/runner/main.cpp @@ -0,0 +1,45 @@ +#include +auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"fterm", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..bdbe7ae Binary files /dev/null and b/windows/runner/resources/app_icon.ico differ diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..a42ea76 --- /dev/null +++ b/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp new file mode 100644 index 0000000..f5bf9fa --- /dev/null +++ b/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp new file mode 100644 index 0000000..041a385 --- /dev/null +++ b/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h new file mode 100644 index 0000000..c86632d --- /dev/null +++ b/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_