diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index dc1e9c7..b9b6207 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -1,39 +1,39 @@
name: "Build APK"
on:
- push:
- branches: ["main"]
- tags: ["*"]
- workflow_dispatch:
+ push:
+ branches: ["main"]
+ tags: ["*"]
+ workflow_dispatch:
jobs:
- build-apk:
- runs-on: ubuntu-latest
+ build-apk:
+ runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
- with:
- submodules: recursive
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ submodules: recursive
- - name: Lix GHA Installer Action
- uses: samueldr/lix-gha-installer-action@v2026-02-22
- with:
- extra_nix_config: experimental-features = nix-command flakes flake-self-attrs
-
- - name: Decode keystore
- run: echo "$KEYSTORE_CONTENT" | base64 --decode > keystore.jks
- env:
- KEYSTORE_CONTENT: ${{ secrets.KEYSTORE_CONTENT }}
+ - name: Lix GHA Installer Action
+ uses: samueldr/lix-gha-installer-action@v2026-02-22
+ with:
+ extra_nix_config: experimental-features = nix-command flakes flake-self-attrs
- - name: Build app
- run: nix develop --command bash -c "flutter pub get && dart scripts/generate.dart && flutter pub run build_runner build && flutter build apk --release"
- env:
- KEYSTORE_PATH: ../../keystore.jks
- KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
+ - name: Decode keystore
+ run: echo "$KEYSTORE_CONTENT" | base64 --decode > keystore.jks
+ env:
+ KEYSTORE_CONTENT: ${{ secrets.KEYSTORE_CONTENT }}
- - name: Upload installer artifact
- uses: actions/upload-artifact@v6
- with:
- name: APK
- path: build/app/outputs/flutter-apk/app-release.apk
\ No newline at end of file
+ - name: Build app
+ run: nix develop --command bash -c "flutter pub get && dart scripts/generate.dart && flutter pub run build_runner build && flutter build apk --target-platform android-arm64 --dart-define=GIT_COMMIT=${{ github.sha }}"
+ env:
+ KEYSTORE_PATH: ../../keystore.jks
+ KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
+
+ - name: Upload installer artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: APK
+ path: build/app/outputs/flutter-apk/app-release.apk
diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml
index d280bc6..c255c8d 100644
--- a/.github/workflows/flatpak.yml
+++ b/.github/workflows/flatpak.yml
@@ -1,37 +1,73 @@
name: "Build Flatpaks"
on:
- push:
- branches: ["main"]
- tags: ["*"]
- workflow_dispatch:
+ push:
+ branches: ["main"]
+ tags: ["*"]
+ workflow_dispatch:
jobs:
- build-flatpak:
- strategy:
- fail-fast: false
- matrix:
- include:
- - arch: x86_64
- runner: ubuntu-latest
- - arch: aarch64
- runner: ubuntu-24.04-arm
- runs-on: ${{ matrix.runner }}
+ build-flatpak:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - arch: x86_64
+ runner: ubuntu-latest
+ - arch: aarch64
+ runner: ubuntu-24.04-arm
+ runs-on: ${{ matrix.runner }}
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
- - name: Lix GHA Installer Action
- uses: samueldr/lix-gha-installer-action@v2026-02-22
- with:
- extra_nix_config: experimental-features = nix-command flakes flake-self-attrs
+ - name: Lix GHA Installer Action
+ uses: samueldr/lix-gha-installer-action@v2026-02-22
+ with:
+ extra_nix_config: experimental-features = nix-command flakes flake-self-attrs
- - name: Build app
- run: nix build .#flatpak
+ - name: Build app
+ run: nix build .#flatpak
- - name: Upload installer artifact
- uses: actions/upload-artifact@v6
- with:
- name: flatpak-${{ matrix.arch }}
- path: result/nexus.federated.nexus.flatpak
\ No newline at end of file
+ - name: Upload installer artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: flatpak-${{ matrix.arch }}
+ path: result/nexus.federated.nexus.flatpak
+
+ publish:
+ needs: build-flatpak
+ if: github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ permissions:
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Install flatpak tooling
+ run: sudo apt-get update && sudo apt-get install -y flatpak ostree
+
+ - name: Download bundles
+ uses: actions/download-artifact@v7
+ with:
+ pattern: flatpak-*
+ path: bundles
+
+ - name: Build OSTree repo
+ run: |
+ ostree init --repo=repo --mode=archive-z2
+ for bundle in bundles/*/nexus.federated.nexus.flatpak; do
+ flatpak build-import-bundle repo "$bundle"
+ done
+ flatpak build-update-repo --prune repo
+
+ - uses: actions/upload-pages-artifact@v4
+ with:
+ path: repo
+
+ - name: Deploy to Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml
new file mode 100644
index 0000000..28344ea
--- /dev/null
+++ b/.github/workflows/ios.yml
@@ -0,0 +1,48 @@
+name: "Build iOS App"
+
+on:
+ push:
+ branches: ["main"]
+ tags: ["*"]
+ workflow_dispatch:
+
+jobs:
+ build-app:
+ runs-on: macos-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ submodules: recursive
+
+ - name: Set up Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ flutter-version: 3.47.4
+
+ - name: Set up Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: gomuks/go.mod
+
+ - name: Build app
+ run: |
+ flutter pub get
+ dart scripts/generate.dart
+ flutter pub run build_runner build
+ flutter build ios --no-codesign --dart-define=GIT_COMMIT=${{ github.sha }}
+
+ # Unsigned IPA: SideStore/AltStore re-sign this on-device with the
+ # user's own Apple ID at install time, so no certificate is needed here.
+ - name: Package unsigned IPA
+ run: |
+ mkdir Payload
+ cp -r build/ios/iphoneos/Runner.app Payload/
+ zip -r Nexus.ipa Payload
+
+ - name: Upload IPA artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: Nexus.ipa
+ path: Nexus.ipa
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
new file mode 100644
index 0000000..b56f16f
--- /dev/null
+++ b/.github/workflows/macos.yml
@@ -0,0 +1,47 @@
+name: "Build MacOS App"
+
+on:
+ push:
+ branches: ["main"]
+ tags: ["*"]
+ workflow_dispatch:
+
+jobs:
+ build-app:
+ runs-on: macos-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ submodules: recursive
+
+ - name: Set up Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ flutter-version: 3.47.4
+
+ - name: Set up Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: gomuks/go.mod
+
+ - name: Build App
+ run: |
+ flutter pub get
+ dart scripts/generate.dart
+ flutter pub run build_runner build
+ flutter build macos --dart-define=GIT_COMMIT=${{ github.sha }}
+
+ - name: Create DMG
+ id: create-dmg
+ uses: L-Super/create-dmg-actions@28511e988b13ca34096d439159a66d468b8e724f
+ with:
+ dmg_name: nexus
+ src_dir: build/macos/Build/Products/Release/Nexus.app
+
+ - name: Upload DMG
+ uses: actions/upload-artifact@v6
+ with:
+ name: nexus.dmg
+ path: ${{ steps.create-dmg.outputs.dmg_path }}
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index d9c8dd5..db339b9 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -1,65 +1,74 @@
name: "Build EXE"
on:
- push:
- branches: ["main"]
- tags: ["*"]
- workflow_dispatch:
+ push:
+ branches: ["main"]
+ tags: ["*"]
+ workflow_dispatch:
jobs:
- build-exe:
- runs-on: windows-latest
+ build-exe:
+ runs-on: windows-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
- with:
- submodules: recursive
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ submodules: recursive
- - name: Set up Flutter
- uses: subosito/flutter-action@v2
- with:
- flutter-version: 3.44.4
+ - name: Set up Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ flutter-version: 3.47.4
- - name: Set up Go
- uses: actions/setup-go@v6
- with:
- go-version-file: gomuks/go.mod
+ - name: Set up Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: gomuks/go.mod
- - name: Setup MSYS2
- uses: msys2/setup-msys2@v2
- with:
- msystem: MINGW64
- install: >-
- mingw-w64-x86_64-gcc
+ - name: Setup MSYS2
+ uses: msys2/setup-msys2@v2
+ with:
+ msystem: CLANG64
+ install: >-
+ mingw-w64-x86_64-gcc
- - name: Go build
- run: |
- cd gomuks/pkg/ffi
- go build -tags goolm,sqlite_fts5 -o ../../../libgomuks.dll -buildmode=c-shared
+ - name: Go build
+ run: |
+ cd gomuks/pkg/ffi
+ go build -tags goolm,sqlite_fts5 -o ../../../libgomuks.dll -buildmode=c-shared
- - name: Build with Flutter
- run: |
- flutter pub get
- dart scripts/generate.dart
- flutter pub run build_runner build
- flutter build windows --release
+ - name: Build with Flutter
+ run: |
+ flutter pub get
+ dart scripts/generate.dart
+ flutter pub run build_runner build
+ flutter build windows --dart-define=GIT_COMMIT=${{ github.sha }}
- - name: Copy MinGW runtime DLLs
- shell: msys2 {0}
- run: |
- cp /mingw64/bin/libgcc_s_seh-1.dll build/windows/x64/runner/Release/
- cp /mingw64/bin/libwinpthread-1.dll build/windows/x64/runner/Release/
- cp /mingw64/bin/libstdc++-6.dll build/windows/x64/runner/Release/
+ - name: Copy MinGW runtime DLLs
+ shell: msys2 {0}
+ run: |
+ cp /mingw64/bin/libgcc_s_seh-1.dll build/windows/x64/runner/Release/
+ cp /mingw64/bin/libwinpthread-1.dll build/windows/x64/runner/Release/
+ cp /mingw64/bin/libstdc++-6.dll build/windows/x64/runner/Release/
- - name: Install Inno Setup
- run: choco install innosetup -y
+ - name: Copy MSVC runtime DLLs
+ shell: powershell
+ run: |
+ $release = "build/windows/x64/runner/Release"
- - name: Build Inno Setup installer
- run: iscc windows/installer.iss
+ Copy-Item C:\Windows\System32\MSVCP140.dll $release -Force
+ Copy-Item C:\Windows\System32\VCRUNTIME140.dll $release -Force
+ Copy-Item C:\Windows\System32\VCRUNTIME140_1.dll $release -Force
- - name: Upload installer artifact
- uses: actions/upload-artifact@v6
- with:
- name: windows-installer
- path: windows/dist/Nexus-Setup.exe
\ No newline at end of file
+ - name: Install Inno Setup
+ run: choco install innosetup -y
+
+ - name: Build Inno Setup installer
+ run: iscc windows/installer.iss
+
+ - name: Upload installer artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: windows-installer
+ path: windows/dist/Nexus-Setup.exe
diff --git a/.gitignore b/.gitignore
index 2bec583..912ced3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,6 @@ key.properties
password.txt
# Nix
-/result
\ No newline at end of file
+/result
+# Widget Preview related
+.widget_preview/
diff --git a/.gitmodules b/.gitmodules
index dc5e02e..06dd51a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
[submodule "gomuks"]
path = gomuks
- url = https://github.com/henry-hiles/gomuks
- branch = main
+ url = https://github.com/gomuks/gomuks
diff --git a/.metadata b/.metadata
index 1be1841..f12453b 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: "nixpkgs000000000000000000000000000000000"
+ revision: "6b182d2c7585eba26d4edce0f97630effd256c33"
channel: "stable"
project_type: app
@@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: nixpkgs000000000000000000000000000000000
- base_revision: nixpkgs000000000000000000000000000000000
- - platform: macos
- create_revision: nixpkgs000000000000000000000000000000000
- base_revision: nixpkgs000000000000000000000000000000000
+ create_revision: 6b182d2c7585eba26d4edce0f97630effd256c33
+ base_revision: 6b182d2c7585eba26d4edce0f97630effd256c33
+ - platform: ios
+ create_revision: 6b182d2c7585eba26d4edce0f97630effd256c33
+ base_revision: 6b182d2c7585eba26d4edce0f97630effd256c33
# User provided section
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..b83039c
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ "configurations": [
+ {
+ "name": "Flutter",
+ "type": "dart",
+ "request": "launch",
+ "program": "lib/main.dart"
+ },
+ {
+ "name": "Flutter (Headless)",
+ "type": "dart",
+ "request": "launch",
+ "program": "lib/main.dart",
+ "env": { "FLUTTER_HEADLESS": "1" }
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 2ff533e..a5cac8a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,7 +10,10 @@
"msgtype",
"muks",
"prefs",
+ "recents",
"unban",
- "unredact"
+ "unifiedpush",
+ "unredact",
+ "webpush"
]
}
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index fb69a56..d9c7c9d 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -21,7 +21,7 @@ See [Effective Dart: Style](https://dart.dev/effective-dart/style) for general r
Controllers live in `lib/controllers/` and provide a source that exposes data and logic via Riverpod providers, allowing other parts of the code to watch state changes with ref.watch (`ref.watch(MyController.provider)`), access the current value with ref.read (`ref.read(MyController.provider)`), and run helper methods on those classes using the notifier:
```dart
-ref.watch(MyController.provider.notifier).helperMethod()
+ref.read(MyController.provider.notifier).helperMethod()
```
We use an object oriented style for controllers, where `provider` is a static member on the controller class. E.g.
diff --git a/README.md b/README.md
index d191d6e..da4a6cb 100644
--- a/README.md
+++ b/README.md
@@ -15,12 +15,22 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
## Progress
-- [ ] Platform Support
+- [x] Platform Support
- [x] Linux
+ - [x] Notifications through UnifiedPush
- [x] Windows
+ - [ ] Background notifications
- [x] Android
- - [ ] MacOS ([#50](https://git.federated.nexus/Nexus/nexus/issues/50))
- - [ ] iOS
+ - [x] Notifications through UnifiedPush
+ - [x] Notifications through FCM
+ - [x] MacOS
+ - [x] Unsigned .ipa
+ - [ ] App Store
+ - [ ] Background notifications
+ - [x] iOS
+ - [x] Unsigned .ipa
+ - [ ] App Store
+ - [ ] Background notifications
- [ ] Web (may not be possible)
- [x] Login (via OAuth)
- [x] Rooms / Spaces
@@ -50,10 +60,10 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] Per message profiles
- [x] Attachments
- [ ] Commands with [MSC4391](https://github.com/matrix-org/matrix-spec-proposals/pull/4391)
- - [x] Mentions
+ - [x] Tags
- [x] Users
- [x] Rooms
- - [ ] Inline emoji picker (Putting this here since it'll be implemented the same way as mentions)
+ - [x] Emojis
- [ ] Custom emojis/stickers
- [ ] GIFs using Gomuks' GIF proxies
- [x] Receiving
@@ -63,9 +73,7 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] URL Previews
- [x] Replies
- [x] Viewing
- - [ ] Jump to original message
- - [x] In loaded timeline
- - [ ] Out of loaded timeline
+ - [x] Jump to original message
- [x] Edits
- [x] Attachments
- [x] Unencrypted
@@ -78,12 +86,10 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] Users
- [x] Clickable
- [x] Rooms
- - [ ] Clickable
+ - [x] Clickable
- [x] Matrix URIs
- [x] Matrix.to links
- [x] Events
- - [ ] Render more nicely
- - [ ] Clickable
- [x] Custom emojis/stickers
- [x] History loading
- [x] Editing
@@ -105,7 +111,8 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] Member list
- [x] Sort by power level
- [ ] Colors based off of power level
-- [ ] Notifications using UnifiedPush ([#35](https://git.federated.nexus/Nexus/nexus/issues/35))
+- [x] Notifications using UnifiedPush ([#35](https://git.federated.nexus/Nexus/nexus/issues/35))
+- [x] Notifications page
- [ ] Group calls using [MSC4195](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
- [ ] Invites
- [x] Settings
@@ -115,10 +122,48 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
If you want to try out Nexus, grab one of the following artifacts from CI:
- [Android APK](https://nightly.link/Henry-Hiles/nexus/workflows/android/main/APK.zip)
+- [Unsigned iOS IPA](https://nightly.link/Henry-Hiles/nexus/workflows/ios/main/Nexus.ipa.zip)
+- [Unsigned MacOS DMG](https://nightly.link/Henry-Hiles/nexus/workflows/macos/main/nexus.dmg.zip)
- [Windows EXE](https://nightly.link/Henry-Hiles/nexus/workflows/windows/main/windows-installer.zip)
-- Flatpak
- - [AArch64/Arm64](https://nightly.link/Henry-Hiles/nexus/workflows/flatpak/main/flatpak-aarch64.zip)
- - [x86_64/AMD64](https://nightly.link/Henry-Hiles/nexus/workflows/flatpak/main/flatpak-x86_64.zip)
+
+Or, use one of the below methods:
+
+### Flatpak
+
+Make sure Flatpak is set up on your system, then run:
+
+```bash
+flatpak install --user https://nexus.federated.nexus/flatpak/nexus.flatpakref
+```
+
+This adds the Nexus remote and installs the app for your user only, so no root access is needed (x86_64 and aarch64 are supported). To install system-wide instead, use `--system` in place of `--user`. Updates arrive through `flatpak update` or your software center.
+
+### NixOS Module
+
+Add Nexus as a flake input, following `nixpkgs` for less fetches:
+
+```nix
+nexus = {
+ url = "git+https://git.federated.nexus/Nexus/nexus";
+ inputs.nixpkgs.follows = "nixpkgs";
+};
+```
+
+Then import the module and enable it in your NixOS configuration:
+
+```nix
+{ inputs, ... }:
+{
+ imports = [ inputs.nexus.nixosModules.default ];
+
+ programs.nexus = {
+ enable = true;
+ enableNotifications = true; # optional: push notifications via UnifiedPush
+ };
+}
+```
+
+This installs Nexus system-wide. With `enableNotifications`, it also installs KUnifiedPush and registers its systemd and D-Bus services so notifications work. The `package` option lets you override the package if you need to.
## Build it yourself
@@ -126,16 +171,17 @@ If you want to try out Nexus, grab one of the following artifacts from CI:
#### Linux
-- With Nix: Either use direnv and `direnv allow`, or `nix flake develop`
-- Without Nix: Install Flutter, Go, Git, Libclang, and Glibc. Do not use any Snap packages, they cause various compilation issues.
+- On NixOS: Either use direnv and `direnv allow`, or `nix develop`
+- On other distros: Install Flutter, Go, Git, Libclang, Libass, MPV, and Glibc. Do not use any Snap packages, they cause various compilation issues.
#### Windows
You will need:
- Flutter
-- Android SDK + NDK
- Git
+- Libass
+- MPV
- Go
- Visual Studio 2022 (Desktop development with C++)
- [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO)
@@ -186,6 +232,12 @@ dart scripts/generate.dart
> export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include"
> ```
+Build webcrypto:
+
+```sh
+flutter pub run webcrypto:setup
+```
+
Build generated files, and watch for new changes:
```sh
@@ -202,7 +254,7 @@ Development instructions can be found in [DEVELOPMENT.md](./DEVELOPMENT.md).
## Community
-Join the [Nexus Client Matrix Room](https://matrix.to/#/#nexus:federated.nexus) for questions or help with developing or using Nexus Client.
+Join the [Nexus Client Matrix room](https://matrix.to/#/#nexus:federated.nexus) for questions or help with developing or using Nexus Client.
# Credits
diff --git a/altstore-source.json b/altstore-source.json
new file mode 100644
index 0000000..4471fb6
--- /dev/null
+++ b/altstore-source.json
@@ -0,0 +1,22 @@
+{
+ "name": "Nexus",
+ "identifier": "nexus.federated.nexus.source",
+ "subtitle": "Nexus for iOS",
+ "description": "Nexus iOS builds for AltStore and SideStore.",
+ "iconURL": "https://git.federated.nexus/Nexus/nexus/raw/branch/main/assets/icon.png",
+ "website": "https://git.federated.nexus/Nexus/nexus",
+ "apps": [
+ {
+ "name": "Nexus",
+ "bundleIdentifier": "nexus.federated.nexus",
+ "developerName": "Nexus",
+ "subtitle": "A Matrix client",
+ "localizedDescription": "Nexus for iOS. Unsigned builds, resigned at install by AltStore/SideStore.",
+ "iconURL": "https://git.federated.nexus/Nexus/nexus/raw/branch/main/assets/icon.png",
+ "category": "social",
+ "screenshots": [],
+ "versions": []
+ }
+ ],
+ "news": []
+}
diff --git a/analysis_options.yaml b/analysis_options.yaml
index a8b1078..00df0c4 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,12 +1,18 @@
analyzer:
- errors:
- invalid_annotation_target: ignore
- avoid_print: ignore
- exclude:
- - "build/**"
- - "**/*.g.dart"
- - "**/*.freezed.dart"
+ errors:
+ invalid_annotation_target: ignore
+ avoid_print: ignore
+ exclude:
+ - "build/**"
+ - "**/*.g.dart"
+ - "**/*.freezed.dart"
+ - android/**
+ - ios/**
+ - web/**
+ - windows/**
+ - macos/**
+ - linux/**
include: package:flutter_lints/flutter.yaml
linter:
- rules:
- prefer_double_quotes: true
\ No newline at end of file
+ rules:
+ prefer_double_quotes: true
diff --git a/android/app/build.gradle b/android/app/build.gradle
deleted file mode 100644
index 2e7fb67..0000000
--- a/android/app/build.gradle
+++ /dev/null
@@ -1,77 +0,0 @@
-plugins {
- id "com.android.application"
- id "kotlin-android"
- // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
- id "dev.flutter.flutter-gradle-plugin"
-}
-
-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file("local.properties")
-if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader("UTF-8") { reader ->
- localProperties.load(reader)
- }
-}
-
-def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
-if (flutterVersionCode == null) {
- flutterVersionCode = "1"
-}
-
-def flutterVersionName = localProperties.getProperty("flutter.versionName")
-if (flutterVersionName == null) {
- flutterVersionName = "1.0"
-}
-
-def keystoreProperties = new Properties()
-def keystorePropertiesFile = rootProject.file('key.properties')
-if (keystorePropertiesFile.exists()) {
- keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
-}
-
-android {
- namespace = "nexus.federated.nexus"
- ndkVersion = flutter.ndkVersion
- compileSdk = 34
-
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_17
- targetCompatibility = JavaVersion.VERSION_17
- }
-
- kotlinOptions {
- jvmTarget = "17"
- }
-
- defaultConfig {
- applicationId = "nexus.federated.nexus"
- minSdk = 29
- targetSdkVersion flutter.targetSdkVersion
- versionCode = flutterVersionCode.toInteger()
- versionName = flutterVersionName
- }
-
- signingConfigs {
- release {
- keyAlias "key"
- def storePath = keystoreProperties['path'] ?: System.getenv("KEYSTORE_PATH")
- storeFile storePath ? file(storePath) : null
- keyPassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD")
- storePassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD")
- }
- }
-
- buildTypes {
- release {
- signingConfig signingConfigs.release
- }
-
- debug {
- applicationIdSuffix = ".debug"
- }
- }
-}
-
-flutter {
- source = "../.."
-}
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
new file mode 100644
index 0000000..9c0d96c
--- /dev/null
+++ b/android/app/build.gradle.kts
@@ -0,0 +1,84 @@
+import java.util.Properties
+
+plugins {
+ id("com.android.application")
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+val keystoreProperties = Properties()
+val keystorePropertiesFile = rootProject.file("key.properties")
+
+if (keystorePropertiesFile.exists()) {
+ keystorePropertiesFile.inputStream().use {
+ keystoreProperties.load(it)
+ }
+}
+
+android {
+ namespace = "nexus.federated.nexus"
+ compileSdk = 36
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ isCoreLibraryDesugaringEnabled = true
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+ }
+
+ defaultConfig {
+ applicationId = "nexus.federated.nexus"
+
+ minSdk = 29
+ targetSdk = flutter.targetSdkVersion
+
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+
+ multiDexEnabled = true
+ }
+
+ signingConfigs {
+ create("release") {
+ keyAlias = "key"
+
+ val storePath =
+ keystoreProperties["path"]?.toString()
+ ?: System.getenv("KEYSTORE_PATH")
+
+ storeFile = storePath?.let { file(it) }
+
+ keyPassword =
+ keystoreProperties["password"]?.toString()
+ ?: System.getenv("KEYSTORE_PASSWORD")
+
+ storePassword =
+ keystoreProperties["password"]?.toString()
+ ?: System.getenv("KEYSTORE_PASSWORD")
+ }
+ }
+
+ buildTypes {
+ release {
+ signingConfig = signingConfigs.getByName("release")
+ }
+
+ debug {
+ applicationIdSuffix = ".debug"
+ }
+ }
+}
+
+dependencies {
+ implementation("org.unifiedpush.android:embedded-fcm-distributor:3.1.0")
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21
+ }
+}
+
+flutter {
+ source = "../.."
+}
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a0a0bcc..d4dbebe 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -6,7 +6,9 @@
+
- if (project.hasProperty("android")) {
- android {
- compileSdkVersion 36
- buildToolsVersion '33.0.1'
- }
- }
- }
-
- project.evaluationDependsOn(":app")
-}
-
-tasks.register("clean", Delete) {
- delete rootProject.buildDir
-}
diff --git a/android/build.gradle.kts b/android/build.gradle.kts
new file mode 100644
index 0000000..441eb71
--- /dev/null
+++ b/android/build.gradle.kts
@@ -0,0 +1,25 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
+rootProject.layout.buildDirectory.value(newBuildDir)
+
+subprojects {
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
+}
+
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 74b269f..5fadfe8 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
deleted file mode 100644
index 7cffcd0..0000000
--- a/android/settings.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-pluginManagement {
- def flutterSdkPath = {
- def properties = new Properties()
- file("local.properties").withInputStream { properties.load(it) }
- def flutterSdkPath = properties.getProperty("flutter.sdk")
- assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
- return flutterSdkPath
- }()
-
- includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
-
- repositories {
- google()
- mavenCentral()
- gradlePluginPortal()
- }
-}
-
-plugins {
- id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "8.13.0" apply false
- id "org.jetbrains.kotlin.android" version "2.2.20" apply false
-}
-
-include ":app"
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
new file mode 100644
index 0000000..b59bc94
--- /dev/null
+++ b/android/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val flutterSdkPath =
+ run {
+ val properties = java.util.Properties()
+ file("local.properties").inputStream().use { properties.load(it) }
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
+ flutterSdkPath
+ }
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+ id("com.android.application") version "9.3.1" apply false
+ id("org.jetbrains.kotlin.android") version "2.4.10" apply false
+}
+
+include(":app")
\ No newline at end of file
diff --git a/assets/icon.svg b/assets/bundled/icon.svg
similarity index 100%
rename from assets/icon.svg
rename to assets/bundled/icon.svg
diff --git a/assets/fonts/AtkinsonHyperlegibleMono.ttf b/assets/fonts/AtkinsonHyperlegibleMono.ttf
new file mode 100644
index 0000000..ac9c7ee
Binary files /dev/null and b/assets/fonts/AtkinsonHyperlegibleMono.ttf differ
diff --git a/assets/fonts/Inter.ttf b/assets/fonts/Inter.ttf
new file mode 100644
index 0000000..4a1af5a
Binary files /dev/null and b/assets/fonts/Inter.ttf differ
diff --git a/assets/fonts/NotoColorEmoji.ttf b/assets/fonts/NotoColorEmoji.ttf
deleted file mode 100644
index b652015..0000000
Binary files a/assets/fonts/NotoColorEmoji.ttf and /dev/null differ
diff --git a/assets/fonts/Roboto.ttf b/assets/fonts/Roboto.ttf
deleted file mode 100644
index 01656a3..0000000
Binary files a/assets/fonts/Roboto.ttf and /dev/null differ
diff --git a/assets/fonts/Twemoji.ttf b/assets/fonts/Twemoji.ttf
new file mode 100644
index 0000000..e389432
Binary files /dev/null and b/assets/fonts/Twemoji.ttf differ
diff --git a/assets/twim/oauth.webp b/assets/twim/oauth.webp
deleted file mode 100644
index 36fbedf..0000000
Binary files a/assets/twim/oauth.webp and /dev/null differ
diff --git a/assets/twim/settings.png b/assets/twim/settings.png
deleted file mode 100644
index 3037be1..0000000
Binary files a/assets/twim/settings.png and /dev/null differ
diff --git a/assets/twim/summary.png b/assets/twim/summary.png
new file mode 100644
index 0000000..70d9a50
Binary files /dev/null and b/assets/twim/summary.png differ
diff --git a/flake.lock b/flake.lock
index 41cfb9d..a48d846 100644
--- a/flake.lock
+++ b/flake.lock
@@ -5,11 +5,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
- "lastModified": 1782949081,
- "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
+ "lastModified": 1788450739,
+ "narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
+ "rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
"type": "github"
},
"original": {
@@ -42,15 +42,16 @@
"nixpkgs": "nixpkgs"
},
"locked": {
- "lastModified": 1774860670,
- "narHash": "sha256-YjJkQrvxrErXtfDi3obUn6rNmkA+CIAZ3f5NgL5xuYE=",
- "owner": "neobrain",
+ "lastModified": 1790870263,
+ "narHash": "sha256-ZBblCzxsUBBCZJRJR0knnaOt2+Xl5JGfI+YkGPf2SI4=",
+ "owner": "Henry-Hiles",
"repo": "nix2flatpak",
- "rev": "61d68e21e3fbc2d57590051f48736bea271f4aba",
+ "rev": "2ef0e3cde2bdce0870f79a7568a72c2681ad20b5",
"type": "github"
},
"original": {
- "owner": "neobrain",
+ "owner": "Henry-Hiles",
+ "ref": "quad/nexus",
"repo": "nix2flatpak",
"type": "github"
}
@@ -73,11 +74,11 @@
},
"nixpkgs-lib": {
"locked": {
- "lastModified": 1782614948,
- "narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=",
+ "lastModified": 1788057806,
+ "narHash": "sha256-DTQSMxzDWmT0zhguthvegnVkn7CFqGCv4IHCzk5ZUpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
- "rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c",
+ "rev": "596e2e3940e09b2abbeb03f75fa1828c57fcd72c",
"type": "github"
},
"original": {
@@ -88,11 +89,11 @@
},
"nixpkgs_2": {
"locked": {
- "lastModified": 1784497964,
- "narHash": "sha256-vlHUuqAcbcH2RKmHbPiuQzbv1pnzzavXnI62RD0bqCU=",
+ "lastModified": 1790689126,
+ "narHash": "sha256-ilerN1WLSvF+HMjziC/Wv99J5y02maDH+6hZPwsORKg=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "241313f4e8e508cb9b13278c2b0fa25b9ca27163",
+ "rev": "b4fd65b198c599cbe814fcb9f42d25d021595ec9",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 2b13a08..97d6068 100644
--- a/flake.nix
+++ b/flake.nix
@@ -5,7 +5,7 @@
self.submodules = true;
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
- nix2flatpak.url = "github:neobrain/nix2flatpak";
+ nix2flatpak.url = "github:Henry-Hiles/nix2flatpak/quad/nexus";
};
outputs =
@@ -16,62 +16,12 @@
...
}@inputs:
flake-parts.lib.mkFlake { inherit inputs; } {
+ imports = [ ./linux/nix ];
systems = [
"x86_64-linux"
"aarch64-linux"
"aarch64-darwin"
"x86_64-darwin"
];
-
- perSystem =
- {
- lib,
- pkgs,
- system,
- ...
- }:
-
- {
- _module.args.pkgs = import nixpkgs {
- inherit system;
- config = {
- android_sdk.accept_license = true;
- allowUnfree = true;
- };
- };
-
- packages =
- let
- default = pkgs.callPackage ./linux/nix/pkg {
- src = self;
- };
- in
- {
- inherit default;
-
- flatpak = inputs.nix2flatpak.lib.${system}.mkFlatpak {
- appName = "Nexus";
- developer = "QuadRadical";
- appId = "nexus.federated.nexus";
- package = default;
- runtime = "org.gnome.Platform/49";
- permissions = {
- share = [ "network" ];
- sockets = [
- "pulseaudio"
- "fallback-x11"
- "wayland"
- ];
- devices = [ "dri" ];
- };
- };
-
- gomuks = pkgs.callPackage ./linux/nix/pkg/gomuks.nix {
- src = self;
- };
- };
-
- devShells.default = pkgs.callPackage ./linux/nix/devshell.nix { };
- };
};
}
diff --git a/gomuks b/gomuks
index c06eb1c..38e5033 160000
--- a/gomuks
+++ b/gomuks
@@ -1 +1 @@
-Subproject commit c06eb1cbda2d49ff199a351e2d55df6ff7ab602b
+Subproject commit 38e5033c3a91db0cbea6cbd9f0feef9ff6441038
diff --git a/hook/build.dart b/hook/build.dart
index 625201d..9315e04 100644
--- a/hook/build.dart
+++ b/hook/build.dart
@@ -1,4 +1,5 @@
import "dart:io";
+
import "package:collection/collection.dart";
import "package:hooks/hooks.dart";
import "package:code_assets/code_assets.dart";
@@ -13,22 +14,46 @@ Future main(List args) => build(args, (input, output) async {
String libFileName;
Map extraEnv = {};
+ IOSSdk? iosSdk;
+ String? iosSdkPath;
+ String? iosTargetTriple;
switch (targetOS) {
case OS.linux:
libFileName = "libgomuks.so";
break;
+ case OS.iOS:
+ // Go only supports buildmode=c-archive for ios, not c-shared, so the
+ // archive built below gets linked into a dylib via a separate clang
+ // invocation before being registered as a normal asset like macOS.
+ libFileName = "libgomuks.dylib";
+ final iosConfig = codeConfig.iOS;
+ iosSdk = iosConfig.targetSdk;
+ final minVersion = iosConfig.targetVersion;
+ iosSdkPath = await getXCodeTool(sdkType: iosSdk.type);
+
+ final archTriple = switch (targetArch) {
+ Architecture.arm64 => "arm64",
+ Architecture.x64 => "x86_64",
+ _ => throw UnsupportedError(
+ "Unsupported iOS architecture: $targetArch",
+ ),
+ };
+
+ iosTargetTriple = iosSdk == IOSSdk.iPhoneSimulator
+ ? "$archTriple-apple-ios$minVersion.0-simulator"
+ : "$archTriple-apple-ios$minVersion.0";
+ extraEnv = {
+ "GOOS": "ios",
+ "CC": await getXCodeTool(sdkType: iosSdk.type, findTool: "clang"),
+ "CGO_CFLAGS": "-isysroot $iosSdkPath -target $iosTargetTriple",
+ "CGO_LDFLAGS": "-isysroot $iosSdkPath -target $iosTargetTriple",
+ };
+ break;
case OS.macOS:
libFileName = "libgomuks.dylib";
extraEnv = {
- "SDKROOT": await getXCodeSDK(),
- "CGO_ENABLED": "1",
- "GOARCH": switch (targetArch) {
- Architecture.arm64 => "arm64",
- Architecture.x64 => "amd64",
- _ => throw UnsupportedError(
- "Unsupported macOS architecture: $targetArch",
- ),
- },
+ "SDKROOT": await getXCodeTool(),
+ "MACOSX_DEPLOYMENT_TARGET": codeConfig.macOS.targetVersion.toString(),
};
break;
case OS.windows:
@@ -96,15 +121,28 @@ Future main(List args) => build(args, (input, output) async {
final tags = [
"sqlite_fts5",
"goolm",
- // goheif/dav1d is not supported on Android, would need to be fixed upstream
- if (targetOS == OS.android) "noheic",
+ // goheif/dav1d is not supported on Android or iOS, would need to be fixed upstream
+ if (targetOS == OS.android || targetOS == OS.iOS) "noheic",
].join(",");
+
+ final archiveFile = targetOS == OS.iOS
+ ? buildDir.resolve("${targetArch.name}/libgomuks.a")
+ : libFile;
print(
- "Building Gomuks shared library $libFileName (${targetOS.name}/${targetArch.name}) to ${libFile.path}...",
+ "Building Gomuks shared library $libFileName (${targetOS.name}/${targetArch.name}) to ${archiveFile.path}...",
);
final result = await Process.run(
"go",
- ["build", "-tags", tags, "-o", libFile.path, "-buildmode=c-shared"],
+ [
+ "build",
+ "-trimpath",
+ "-ldflags=-s -w",
+ "-tags",
+ tags,
+ "-o",
+ archiveFile.path,
+ "-buildmode=${targetOS == OS.iOS ? "c-archive" : "c-shared"}",
+ ],
workingDirectory: gomuksBuildDir.resolve("pkg/ffi/").toFilePath(),
environment: {
"CGO_ENABLED": "1",
@@ -124,6 +162,35 @@ Future main(List args) => build(args, (input, output) async {
"Failed to build Gomuks shared library\n${result.stderr}",
);
}
+
+ if (targetOS == OS.iOS) {
+ print("Linking $archiveFile into $libFile...");
+ final linkResult = await Process.run("xcrun", [
+ "--sdk",
+ iosSdk!.type,
+ "clang",
+ "-dynamiclib",
+ "-isysroot",
+ iosSdkPath!,
+ "-target",
+ iosTargetTriple!,
+ "-install_name",
+ "@rpath/libgomuks.dylib",
+ "-framework",
+ "Security",
+ "-framework",
+ "CoreFoundation",
+ "-framework",
+ "SystemConfiguration",
+ "-force_load",
+ archiveFile.path,
+ "-o",
+ libFile.path,
+ ]);
+ if (linkResult.exitCode != 0) {
+ throw Exception("Failed to link Gomuks dylib\n${linkResult.stderr}");
+ }
+ }
}
final generatedFile = "src/third_party/gomuks.g.dart";
diff --git a/ios/.gitignore b/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..391a902
--- /dev/null
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+
+
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..ec97fc6
--- /dev/null
+++ b/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..c4855bf
--- /dev/null
+++ b/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..620e46e
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,43 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '13.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..b29d5cb
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,28 @@
+PODS:
+ - Flutter (1.0.0)
+ - media_kit_libs_ios_video (1.0.4):
+ - Flutter
+ - media_kit_video (0.0.1):
+ - Flutter
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
+ - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ media_kit_libs_ios_video:
+ :path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
+ media_kit_video:
+ :path: ".symlinks/plugins/media_kit_video/ios"
+
+SPEC CHECKSUMS:
+ Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
+ media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
+ media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
+
+PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
+
+COCOAPODS: 1.17.0
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..065d08b
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,759 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 2ADFEE6C745FFB2100CC9AFD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8156A45F510382D558AED93A /* Pods_RunnerTests.framework */; };
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
+ 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
+ 88D55A5F1C7625122EBEE29D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82F9A3759658343C81A0EA4C /* Pods_Runner.framework */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 22DE4310DAFBE211CDF700B1 /* 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 = ""; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 363A89F6FA09BCCBDED440CE /* 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 = ""; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 8156A45F510382D558AED93A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 82F9A3759658343C81A0EA4C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AEB96D8976BD46D6860C7041 /* 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 = ""; };
+ B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
+ FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8C0A36760DA8B873D8F6DDCE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ADFEE6C745FFB2100CC9AFD /* Pods_RunnerTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
+ 88D55A5F1C7625122EBEE29D /* Pods_Runner.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1CFFAE23B502BCCEB2B191A3 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ AEB96D8976BD46D6860C7041 /* Pods-Runner.debug.xcconfig */,
+ 363A89F6FA09BCCBDED440CE /* Pods-Runner.release.xcconfig */,
+ 22DE4310DAFBE211CDF700B1 /* Pods-Runner.profile.xcconfig */,
+ B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */,
+ FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */,
+ 63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ sourceTree = "";
+ };
+ 594EB1F65336CF9C7958F6FA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 82F9A3759658343C81A0EA4C /* Pods_Runner.framework */,
+ 8156A45F510382D558AED93A /* Pods_RunnerTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
+ 1CFFAE23B502BCCEB2B191A3 /* Pods */,
+ 594EB1F65336CF9C7958F6FA /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ EE82EC529EB6C0F1FA480659 /* [CP] Check Pods Manifest.lock */,
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ 8C0A36760DA8B873D8F6DDCE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 0830C6758DA3ECA81FB12386 /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ 1D165FDFB9D0D939B041966D /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ packageProductDependencies = (
+ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
+ );
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1510;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ packageReferences = (
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
+ );
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 0830C6758DA3ECA81FB12386 /* [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;
+ };
+ 1D165FDFB9D0D939B041966D /* [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;
+ };
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+ EE82EC529EB6C0F1FA480659 /* [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-RunnerTests-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 */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ 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_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ 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_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = PK66NJM372;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Debug;
+ };
+ 331C8089294A63A400263BE5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Release;
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ 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_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ 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_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ 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_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ 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_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ 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_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = PK66NJM372;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = PK66NJM372;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = nexus.federated.nexus;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug */,
+ 331C8089294A63A400263BE5 /* Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = FlutterGeneratedPluginSwiftPackage;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..c3fedb2
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..c73d4ae
--- /dev/null
+++ b/ios/Runner/AppDelegate.swift
@@ -0,0 +1,17 @@
+import Flutter
+import UIKit
+
+@main
+@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+
+ func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
+ GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d0d98aa
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1 @@
+{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..1682af0
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..51f4a9b
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..97b3b3f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..17d971e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..ca74554
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..6129702
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..16c3d1e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..97b3b3f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..f515ebd
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..2e49a13
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
new file mode 100644
index 0000000..66b9ef2
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
new file mode 100644
index 0000000..53af9ff
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
new file mode 100644
index 0000000..455803d
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
new file mode 100644
index 0000000..7a2fd0f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..2e49a13
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..c34ad9e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
new file mode 100644
index 0000000..5e21545
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
new file mode 100644
index 0000000..2140e17
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..a27d854
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..8b4eb75
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..21c424b
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
new file mode 100644
index 0000000..7680b42
--- /dev/null
+++ b/ios/Runner/Info.plist
@@ -0,0 +1,79 @@
+
+
+
+
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Nexus
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ nexus
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ nexus.federated.nexus
+
+
+
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneClassName
+ UIWindowScene
+ UISceneConfigurationName
+ flutter
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+ UISceneStoryboardFile
+ Main
+
+
+
+
+ UIApplicationSupportsIndirectInputEvents
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/ios/Runner/SceneDelegate.swift b/ios/Runner/SceneDelegate.swift
new file mode 100644
index 0000000..b9ce8ea
--- /dev/null
+++ b/ios/Runner/SceneDelegate.swift
@@ -0,0 +1,6 @@
+import Flutter
+import UIKit
+
+class SceneDelegate: FlutterSceneDelegate {
+
+}
diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/lib/controllers/account_data.dart b/lib/controllers/account_data.dart
index 0926e08..c595565 100644
--- a/lib/controllers/account_data.dart
+++ b/lib/controllers/account_data.dart
@@ -1,16 +1,22 @@
+import "dart:convert";
+
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/models/account_data.dart";
-class AccountDataController extends Notifier> {
+class AccountDataController extends Notifier {
@override
- IMap build() => .new();
+ AccountData build() => .new();
- void update(IMap newData) =>
- state = .new({...state.unlock, ...newData.unlock});
+ void update(IMap> newAccountData) =>
+ state = .fromJson({
+ ...json.decode(json.encode(state.toJson())),
+ ...newAccountData
+ .map((key, value) => MapEntry(key, value["content"]))
+ .unlock,
+ });
- static final provider =
- NotifierProvider>(
- AccountDataController.new,
- );
+ static final provider = NotifierProvider(
+ AccountDataController.new,
+ );
}
diff --git a/lib/controllers/attachment.dart b/lib/controllers/attachment.dart
index e33493e..d4a5e09 100644
--- a/lib/controllers/attachment.dart
+++ b/lib/controllers/attachment.dart
@@ -6,10 +6,8 @@ import "package:nexus/models/content/content.dart";
import "package:nexus/models/content/message.dart";
import "package:path/path.dart";
-class AttachmentController extends Notifier<(String, MessageContent?)?> {
- final String roomId;
- AttachmentController(this.roomId);
-
+class AttachmentController(final String roomId)
+ extends Notifier<(String, MessageContent?)?> {
@override
Null build() => null;
@@ -17,18 +15,16 @@ class AttachmentController extends Notifier<(String, MessageContent?)?> {
final filename = basename(file.path);
state = (filename, null);
- final room = ref.watch(
- RoomsController.provider.select((value) => value[roomId]),
+ final isEncrypted = ref.read(
+ RoomsController.provider.select(
+ (value) =>
+ value[roomId]?.state[EventType.encryption.type]?.isNotEmpty == true,
+ ),
);
final content = await ref
.watch(ClientController.provider.notifier)
- .uploadMedia(
- .new(
- path: file.path,
- encrypt: room?.state[EventType.encryption.type]?.isNotEmpty == true,
- ),
- );
+ .uploadMedia(.new(path: file.path, encrypt: isEncrypted));
state = (filename, content);
}
diff --git a/lib/controllers/auth_url.dart b/lib/controllers/auth_url.dart
index 156eb81..963df86 100644
--- a/lib/controllers/auth_url.dart
+++ b/lib/controllers/auth_url.dart
@@ -4,10 +4,8 @@ import "package:nexus/controllers/client_id.dart";
import "package:nexus/models/oauth_auth_code_response.dart";
import "package:nexus/models/requests/oauth/get_auth_url.dart";
-class AuthUrlController extends AsyncNotifier {
- final Uri homeserver;
- AuthUrlController(this.homeserver);
-
+class AuthUrlController(final Uri homeserver)
+ extends AsyncNotifier {
@override
Future build() async => ref
.watch(ClientController.provider.notifier)
diff --git a/lib/controllers/author.dart b/lib/controllers/author.dart
index bbbe068..f9c9167 100644
--- a/lib/controllers/author.dart
+++ b/lib/controllers/author.dart
@@ -1,19 +1,17 @@
import "dart:async";
+
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/user.dart";
import "package:nexus/models/content/membership.dart";
import "package:nexus/models/event.dart";
-class AuthorController extends AsyncNotifier {
- final Event event;
- AuthorController(this.event);
-
+class AuthorController(final Event event)
+ extends AsyncNotifier {
@override
Future build() async {
final member = await ref.watch(
- UserController.provider(
- .new(roomId: event.roomId, userId: event.sender),
- ).future,
+ UserController.provider(.new(roomId: event.roomId, userId: event.sender))
+ .future,
);
return .new(
diff --git a/lib/controllers/client.dart b/lib/controllers/client.dart
index 2cb1d66..7d9604b 100644
--- a/lib/controllers/client.dart
+++ b/lib/controllers/client.dart
@@ -1,42 +1,50 @@
+import "dart:async";
import "dart:ffi";
import "dart:io";
import "dart:isolate";
import "dart:math";
+
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:ffi/ffi.dart";
-import "package:flutter/foundation.dart";
-import "package:nexus/controllers/account_data.dart";
-import "package:nexus/controllers/client_state.dart";
-import "package:nexus/controllers/init_complete.dart";
-import "package:nexus/controllers/rooms.dart";
-import "package:nexus/controllers/space_edges.dart";
-import "package:nexus/controllers/sync_status.dart";
-import "package:nexus/controllers/top_level_spaces.dart";
+import "package:flutter/cupertino.dart";
+import "package:intl/intl.dart";
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
-import "package:nexus/main.dart";
+import "package:nexus/models/capabilities.dart";
import "package:nexus/models/content/message.dart";
import "package:nexus/models/event.dart";
+import "package:nexus/models/event_context.dart";
+import "package:nexus/models/gomuks_config.dart";
import "package:nexus/models/oauth_auth_code_response.dart";
+import "package:nexus/models/open_graph_data.dart";
import "package:nexus/models/paginate.dart";
+import "package:nexus/models/paginate_manual.dart";
+import "package:nexus/models/requests/deregister_pusher.dart";
import "package:nexus/models/requests/download_media.dart";
import "package:nexus/models/requests/get_event.dart";
+import "package:nexus/models/requests/get_event_context.dart";
+import "package:nexus/models/requests/get_mentions.dart";
import "package:nexus/models/requests/get_related_events.dart";
import "package:nexus/models/requests/get_room_state.dart";
import "package:nexus/models/requests/join_room.dart";
-import "package:nexus/models/profile.dart";
+import "package:nexus/models/profile_response.dart";
import "package:nexus/models/requests/oauth/exchange_token.dart";
import "package:nexus/models/requests/oauth/get_auth_url.dart";
import "package:nexus/models/requests/oauth/register_client.dart";
import "package:nexus/models/requests/paginate.dart";
+import "package:nexus/models/requests/paginate_manual.dart";
import "package:nexus/models/requests/redact_event.dart";
+import "package:nexus/models/requests/register_pusher.dart";
import "package:nexus/models/requests/report.dart";
import "package:nexus/models/requests/send_event.dart";
import "package:nexus/models/requests/send_message.dart";
+import "package:nexus/models/requests/set_account_data.dart";
import "package:nexus/models/requests/set_membership.dart";
import "package:nexus/models/requests/set_state.dart";
import "package:nexus/models/requests/upload_media.dart";
import "package:nexus/models/room.dart";
-import "package:nexus/models/sync_data.dart";
+import "package:nexus/models/room_metadata.dart";
+import "package:nexus/models/room_summary.dart";
+import "package:nexus/models/spec_versions_response.dart";
import "package:nexus/src/third_party/gomuks.g.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:path_provider/path_provider.dart";
@@ -44,134 +52,101 @@ import "package:path_provider/path_provider.dart";
class ClientController extends AsyncNotifier {
@override
Future build() async {
- final Pointer root;
- if (Platform.isAndroid) {
- final dir = await getApplicationSupportDirectory();
- root = "${dir.path}/gomuks".toNativeUtf8().cast();
- } else {
- root = nullptr.cast();
+ debugPrint("Setting Gomuks env...");
+ if (Platform.isAndroid || Platform.isIOS) {
+ final env = {
+ "GOMUKS_ROOT": (await getApplicationSupportDirectory()).path,
+ "GOMUKS_CACHE_HOME": (await getApplicationCacheDirectory()).path,
+ };
+ for (final MapEntry(:key, :value) in env.entries) {
+ final keyPtr = key.toNativeUtf8().cast();
+ final valuePtr = value.toNativeUtf8().cast();
+ try {
+ GomuksSetEnv(keyPtr, valuePtr);
+ } finally {
+ calloc
+ ..free(keyPtr)
+ ..free(valuePtr);
+ }
+ }
}
- final handle = GomuksInit(root);
+ debugPrint("Initializing Gomuks...");
+ final handle = await Isolate.run(() {
+ final bufferPointer = GomuksConfig(
+ matrix: .new(
+ initialDeviceDisplayName:
+ "Nexus on ${toBeginningOfSentenceCase(Platform.operatingSystem)}",
+ ),
+ ).toJson().toGomuksBufferPtr();
- final callable =
- NativeCallable<
- Void Function(Pointer, Int64, GomuksOwnedBuffer)
- >.listener((
- Pointer command,
- int requestId,
- GomuksOwnedBuffer data,
- ) {
- try {
- final muksEventType = command.cast().toDartString();
- debugPrint("Handling $muksEventType...");
- final decodedMuksEvent = data.toJson();
-
- switch (muksEventType) {
- case "client_state":
- ref
- .watch(ClientStateController.provider.notifier)
- .set(.fromJson(decodedMuksEvent));
- break;
- case "sync_status":
- ref
- .watch(SyncStatusController.provider.notifier)
- .set(.fromJson(decodedMuksEvent));
- break;
- case "init_complete":
- ref.watch(InitCompleteController.provider.notifier).complete();
- break;
- case "send_complete":
- final event = Event.fromJson(decodedMuksEvent["event"]);
- ref
- .watch(RoomsController.provider.notifier)
- .update(
- .new({
- event.roomId: .new(events: .new({event.rowId: event})),
- }),
- .new(),
- );
-
- break;
- case "sync_complete":
- final syncData = SyncData.fromJson(decodedMuksEvent);
- final roomProvider = RoomsController.provider;
- final accountDataProvider = AccountDataController.provider;
-
- if (syncData.clearState) {
- ref.invalidate(roomProvider);
- ref.invalidate(accountDataProvider);
- }
-
- ref
- .watch(roomProvider.notifier)
- .update(syncData.rooms, syncData.leftRooms);
- ref
- .watch(accountDataProvider.notifier)
- .update(syncData.accountData);
-
- if (syncData.topLevelSpaces != null) {
- ref
- .watch(TopLevelSpacesController.provider.notifier)
- .set(syncData.topLevelSpaces!);
- }
-
- if (syncData.spaceEdges != null) {
- ref
- .watch(SpaceEdgesController.provider.notifier)
- .set(syncData.spaceEdges!);
- }
-
- // ref
- // .watch(SyncStatusController.provider.notifier)
- // .set(SyncStatus.fromJson(decodedMuksEvent));
- break;
- default:
- debugPrint("Unhandled event: $muksEventType");
- }
- debugPrint("Finished handling $muksEventType...");
- } catch (error, stackTrace) {
- if (kDebugMode) {
- debugPrintStack(stackTrace: stackTrace, label: error.toString());
- rethrow;
- } else {
- showError(error, stackTrace);
- }
- }
- });
+ try {
+ return GomuksInit(bufferPointer.ref);
+ } finally {
+ calloc
+ ..free(bufferPointer.ref.base)
+ ..free(bufferPointer);
+ }
+ });
ref.onDispose(() => GomuksDestroy(handle));
- ref.onDispose(callable.close);
- final errorCode = GomuksStart(handle, callable.nativeFunction);
+ return handle;
+ }
- if (errorCode == 0) return handle;
- throw Exception("GomuksStart returned error code $errorCode");
+ Future callGomuksMethod(
+ Map data,
+ FutureOr Function(int handle, GomuksBorrowedBuffer data)
+ callback,
+ ) async {
+ final bufferPointer = data.toGomuksBufferPtr();
+
+ try {
+ final handle = await future;
+
+ final response = await Isolate.run(
+ () => callback(handle, bufferPointer.ref),
+ );
+
+ final json = response.buf.toJsonAndFree();
+
+ if (response.command.cast().toDartString() == "error") {
+ throw json;
+ }
+
+ return json;
+ } finally {
+ calloc
+ ..free(bufferPointer.ref.base)
+ ..free(bufferPointer);
+ }
+ }
+
+ Future<(Event, RoomMetadata)?> handlePush(Map data) async {
+ final response = await callGomuksMethod(
+ data,
+ (handle, data) async => GomuksHandlePush(handle, data),
+ );
+
+ return response == null
+ ? null
+ : (
+ Event.fromJson(response["event"]),
+ RoomMetadata.fromJson(response["room"]),
+ );
}
Future _sendCommand(
String command, [
Map data = const {},
- ]) async {
- final bufferPointer = data.toGomuksBufferPtr();
- final handle = await future;
- final response = await Isolate.run(
- () => GomuksSubmitCommand(
- handle,
- command.toNativeUtf8().cast(),
- bufferPointer.ref,
- ),
- );
-
- calloc.free(bufferPointer);
-
- final json = response.buf.toJson();
- if (response.command.cast().toDartString() == "error") {
- throw json;
+ ]) => callGomuksMethod(data, (handle, data) {
+ final commandPointer = command.toNativeUtf8().cast();
+ try {
+ return GomuksSubmitCommand(handle, commandPointer, data);
+ } finally {
+ calloc.free(commandPointer);
}
-
- return json;
- }
+ });
Future redactEvent(RedactEventRequest report) =>
_sendCommand("redact_event", report.toJson());
@@ -183,7 +158,7 @@ class ClientController extends AsyncNotifier {
final json = request.toJson();
final content = request.content.toJson();
- return Event.fromJson(
+ return .fromJson(
await _sendCommand("send_event", {
...json,
"content": {
@@ -210,26 +185,17 @@ class ClientController extends AsyncNotifier {
}
}
- Future joinRoom(JoinRoomRequest request) async {
- final response = await _sendCommand("join_room", request.toJson());
- return response["room_id"];
- }
+ Future joinRoom(JoinRoomRequest request) async =>
+ (await _sendCommand("join_room", request.toJson()))["room_id"];
- Future getAccessToken() async {
- final response = await _sendCommand("get_account_info", {});
- return response?["access_token"];
- }
+ Future getRoomSummary(JoinRoomRequest request) async =>
+ .fromJson(await _sendCommand("get_room_summary", request.toJson()));
Future leaveRoom(Room room) async {
if (room.metadata == null) return;
await _sendCommand("leave_room", {"room_id": room.metadata!.id});
}
- // (await _sendCommand("get_event_context", {
- // "room_id": request.roomId,
- // "event_id": r"$OqZT4NuTj0J1-771IOEEWRI4XdumRNu6ighlvO3K3gc",
- // }));
-
Future> getRoomState(GetRoomStateRequest request) async {
Future getState(GetRoomStateRequest request) async =>
(await _sendCommand("get_room_state", request.toJson())) as List?;
@@ -250,17 +216,35 @@ class ClientController extends AsyncNotifier {
return .new(response?.map((event) => .fromJson(event)));
}
+ Future> getMentions(GetMentionsRequest request) async => .new(
+ // TODO: Handle `related_events`
+ ((await _sendCommand("get_mentions", request.toJson()))["events"] as List)
+ .map((event) => .fromJson(event)),
+ );
+
Future getEvent(GetEventRequest request) async {
final json = await _sendCommand("get_event", request.toJson());
return json == null ? null : .fromJson(json);
}
+ Future getUrlPreview(Uri url) async =>
+ .fromJson(await _sendCommand("get_url_preview", {"url": url.toString()}));
+
Future paginate(PaginateRequest request) async =>
.fromJson(await _sendCommand("paginate", request.toJson()));
- Future getProfile(String userId) async {
- final json = await _sendCommand("get_profile", {"user_id": userId});
- return .fromJsonWithCatch({...json, "id": userId});
+ Future paginateManual(PaginateManualRequest request) async =>
+ .fromJson(await _sendCommand("paginate_manual", request.toJson()));
+
+ Future getEventContext(GetEventContextRequest request) async =>
+ .fromJson(await _sendCommand("get_event_context", request.toJson()));
+
+ Future getProfile(String userId) async {
+ try {
+ return .fromJson(await _sendCommand("get_profile", {"user_id": userId}));
+ } catch (_) {
+ return .new(profile: .new(id: userId));
+ }
}
Future reportEvent(ReportRequest request) =>
@@ -269,6 +253,18 @@ class ClientController extends AsyncNotifier {
Future setMembership(SetMembershipRequest request) =>
_sendCommand("set_membership", request.toJson());
+ Future setAccountData(SetAccountDataRequest request) =>
+ _sendCommand("set_account_data", request.toJson());
+
+ Future registerPusher(RegisterPusherRequest request) =>
+ _sendCommand("register_homeserver_push", request.toJson());
+
+ Future deregisterPusher(DeregisterPusherRequest request) =>
+ _sendCommand("register_homeserver_push", {
+ ...request.toJson(),
+ "kind": null,
+ });
+
Future uploadMedia(UploadMediaRequest request) async =>
.fromJson(await _sendCommand("upload_media", request.toJson()));
@@ -278,9 +274,11 @@ class ClientController extends AsyncNotifier {
Future logout() => _sendCommand("logout");
Future markRead(Room room) async {
+ if (room.timeline.isEmpty || room.metadata == null) return;
final eventRowId = room.timeline[room.timeline.keys.reduce(max)];
final event = eventRowId == null ? null : room.events[eventRowId];
- if (event == null || room.metadata == null) return;
+
+ if (event == null) return;
await _sendCommand("mark_read", {
"room_id": room.metadata!.id,
@@ -303,10 +301,16 @@ class ClientController extends AsyncNotifier {
Future exchangeToken(OAuthExchangeTokenRequest request) async =>
await _sendCommand("oauth_exchange_token", request.toJson());
+ Future getSpecVersions() async =>
+ .fromJson(await _sendCommand("get_versions"));
+
+ Future getCapabilities() async =>
+ .fromJson((await _sendCommand("get_capabilities"))["capabilities"]);
+
Future discoverHomeserver(Uri homeserver) async {
try {
final response = await _sendCommand("discover_homeserver", {
- "user_id": "@fake-user:${homeserver.host}",
+ "user_id": "@fake-user:${homeserver.authority}",
});
return Uri.parse(response["m.homeserver"]?["base_url"]);
} catch (error) {
diff --git a/lib/controllers/client_id.dart b/lib/controllers/client_id.dart
index ac8f5cb..7748f97 100644
--- a/lib/controllers/client_id.dart
+++ b/lib/controllers/client_id.dart
@@ -1,10 +1,7 @@
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/client.dart";
-class ClientIdController extends AsyncNotifier {
- final Uri homeserver;
- ClientIdController(this.homeserver);
-
+class ClientIdController(final Uri homeserver) extends AsyncNotifier {
@override
Future build() => ref
.watch(ClientController.provider.notifier)
diff --git a/lib/controllers/emoji.dart b/lib/controllers/emoji.dart
deleted file mode 100644
index f1a5c79..0000000
--- a/lib/controllers/emoji.dart
+++ /dev/null
@@ -1,121 +0,0 @@
-import "dart:convert";
-import "package:collection/collection.dart";
-import "package:fast_immutable_collections/fast_immutable_collections.dart";
-import "package:flutter/foundation.dart";
-import "package:flutter/material.dart";
-import "package:flutter_riverpod/flutter_riverpod.dart";
-import "package:http/http.dart";
-import "package:nexus/models/gemoji.dart";
-
-class EmoteSection {
- final String category;
- final String label;
- final IconData icon;
- final List items;
- final bool isRecent;
-
- const EmoteSection({
- required this.category,
- required this.label,
- required this.icon,
- required this.items,
- this.isRecent = false,
- });
-}
-
-class EmoteItem {
- final String id;
- final String display;
- final List keywords;
- final int useCounter;
- final Image? customImage;
-
- const EmoteItem({
- required this.id,
- required this.display,
- required this.keywords,
- required this.useCounter,
- this.customImage,
- });
-}
-
-class EmojiController extends AsyncNotifier> {
- @override
- Future> build() async {
- final response = await get(
- .https("github.com", "github/gemoji/raw/refs/heads/master/db/emoji.json"),
- );
-
- if (response.statusCode != 200) {
- throw Exception("Failed to load emoji data");
- }
-
- return compute(parseEmojiJson, response.body);
- }
-
- static IList parseEmojiJson(String body) {
- final data = json.decode(body) as List;
- final allEntries = data
- .cast