Rebrand application as Qlyra
Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s

This commit is contained in:
sevenhill
2026-08-30 13:16:17 +03:00
parent 0245f792de
commit f74057ce9b
592 changed files with 38233 additions and 1899 deletions
+1 -1
View File
@@ -42,6 +42,6 @@
## Проверка
- [ ] `flutter analyze`
- [ ] Сборка `komet` flavor
- [ ] Сборка `qlyra` flavor
- [ ] Ручная проверка затронутых сценариев
- [ ] Регресс по безопасности (если затронута)
+1 -1
View File
@@ -21,4 +21,4 @@ runs:
- name: Cache Rust build
uses: Swatinem/rust-cache@v2
with:
workspaces: native/komet_crypto/rust
workspaces: native/qlyra_crypto/rust
+8 -8
View File
@@ -69,12 +69,12 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
@@ -87,7 +87,7 @@ jobs:
- name: Upload Universal APK
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-universal
name: qlyra-android-fcm-universal
path: build/app/outputs/flutter-apk/app-oneme-release.apk
if-no-files-found: error
retention-days: 30
@@ -95,7 +95,7 @@ jobs:
- name: Upload arm64-v8a APK
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-arm64-v8a
name: qlyra-android-fcm-arm64-v8a
path: build/app/outputs/flutter-apk/app-arm64-v8a-oneme-release.apk
if-no-files-found: error
retention-days: 30
@@ -103,7 +103,7 @@ jobs:
- name: Upload armeabi-v7a APK
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-armeabi-v7a
name: qlyra-android-fcm-armeabi-v7a
path: build/app/outputs/flutter-apk/app-armeabi-v7a-oneme-release.apk
if-no-files-found: error
retention-days: 30
@@ -111,7 +111,7 @@ jobs:
- name: Upload x86_64 APK
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-x86_64
name: qlyra-android-fcm-x86_64
path: build/app/outputs/flutter-apk/app-x86_64-oneme-release.apk
if-no-files-found: error
retention-days: 30
@@ -122,7 +122,7 @@ jobs:
- name: Upload App Bundle artifact
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-aab
name: qlyra-android-fcm-aab
path: build/app/outputs/bundle/onemeRelease/app-oneme-release.aab
if-no-files-found: error
retention-days: 30
@@ -130,7 +130,7 @@ jobs:
- name: Upload debug symbols
uses: actions/upload-artifact@v4
with:
name: komet-android-fcm-symbols
name: qlyra-android-fcm-symbols
path: build/symbols
if-no-files-found: error
retention-days: 90
+16 -16
View File
@@ -69,68 +69,68 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
- name: Build Universal APK
run: flutter build apk --release --flavor komet --obfuscate --split-debug-info=build/symbols
run: flutter build apk --release --flavor qlyra --obfuscate --split-debug-info=build/symbols
- name: Build Split APKs
run: flutter build apk --release --split-per-abi --flavor komet --obfuscate --split-debug-info=build/symbols
run: flutter build apk --release --split-per-abi --flavor qlyra --obfuscate --split-debug-info=build/symbols
- name: Upload Universal APK
uses: actions/upload-artifact@v4
with:
name: komet-android-universal
path: build/app/outputs/flutter-apk/app-komet-release.apk
name: qlyra-android-universal
path: build/app/outputs/flutter-apk/app-qlyra-release.apk
if-no-files-found: error
retention-days: 30
- name: Upload arm64-v8a APK
uses: actions/upload-artifact@v4
with:
name: komet-android-arm64-v8a
path: build/app/outputs/flutter-apk/app-arm64-v8a-komet-release.apk
name: qlyra-android-arm64-v8a
path: build/app/outputs/flutter-apk/app-arm64-v8a-qlyra-release.apk
if-no-files-found: error
retention-days: 30
- name: Upload armeabi-v7a APK
uses: actions/upload-artifact@v4
with:
name: komet-android-armeabi-v7a
path: build/app/outputs/flutter-apk/app-armeabi-v7a-komet-release.apk
name: qlyra-android-armeabi-v7a
path: build/app/outputs/flutter-apk/app-armeabi-v7a-qlyra-release.apk
if-no-files-found: error
retention-days: 30
- name: Upload x86_64 APK
uses: actions/upload-artifact@v4
with:
name: komet-android-x86_64
path: build/app/outputs/flutter-apk/app-x86_64-komet-release.apk
name: qlyra-android-x86_64
path: build/app/outputs/flutter-apk/app-x86_64-qlyra-release.apk
if-no-files-found: error
retention-days: 30
- name: Build App Bundle
run: flutter build appbundle --release --flavor komet --obfuscate --split-debug-info=build/symbols
run: flutter build appbundle --release --flavor qlyra --obfuscate --split-debug-info=build/symbols
- name: Upload App Bundle artifact
uses: actions/upload-artifact@v4
with:
name: komet-android-aab
path: build/app/outputs/bundle/kometRelease/app-komet-release.aab
name: qlyra-android-aab
path: build/app/outputs/bundle/qlyraRelease/app-qlyra-release.aab
if-no-files-found: error
retention-days: 30
- name: Upload debug symbols
uses: actions/upload-artifact@v4
with:
name: komet-android-symbols
name: qlyra-android-symbols
path: build/symbols
if-no-files-found: error
retention-days: 90
+8 -8
View File
@@ -54,14 +54,14 @@ jobs:
run: |
mkdir -p dist build/ios/Payload
cp -R build/ios/iphoneos/Runner.app build/ios/Payload/
(cd build/ios && zip -qr ../../dist/Komet-ios-unsigned.ipa Payload)
(cd build/ios && zip -qr ../../dist/Qlyra-ios-unsigned.ipa Payload)
rm -rf build/ios/Payload
- name: Upload unsigned iOS artifact
uses: actions/upload-artifact@v4
with:
name: komet-ios-unsigned
path: dist/Komet-ios-unsigned.ipa
name: qlyra-ios-unsigned
path: dist/Qlyra-ios-unsigned.ipa
if-no-files-found: error
retention-days: 30
@@ -79,9 +79,9 @@ jobs:
<plist version="1.0">
<dict>
<key>get-task-allow</key><true/>
<key>application-identifier</key><string>ru.komet.app</string>
<key>application-identifier</key><string>ru.qlyra.app</string>
<key>keychain-access-groups</key>
<array><string>ru.komet.app</string></array>
<array><string>ru.qlyra.app</string></array>
</dict>
</plist>
PLIST
@@ -104,12 +104,12 @@ jobs:
run: |
mkdir -p dist build/ios/Payload
cp -R build/ios/iphoneos/Runner.app build/ios/Payload/
(cd build/ios && zip -qr ../../dist/Komet-ios-pseudosigned.ipa Payload)
(cd build/ios && zip -qr ../../dist/Qlyra-ios-pseudosigned.ipa Payload)
- name: Upload iOS artifact
uses: actions/upload-artifact@v4
with:
name: komet-ios-pseudosigned
path: dist/Komet-ios-pseudosigned.ipa
name: qlyra-ios-pseudosigned
path: dist/Qlyra-ios-pseudosigned.ipa
if-no-files-found: error
retention-days: 30
+3 -3
View File
@@ -56,12 +56,12 @@ jobs:
- name: Package Linux
run: |
mkdir -p dist
tar -C build/linux/x64/release/bundle -czf dist/Komet-linux-x64.tar.gz .
tar -C build/linux/x64/release/bundle -czf dist/Qlyra-linux-x64.tar.gz .
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
name: komet-linux-x64
path: dist/Komet-linux-x64.tar.gz
name: qlyra-linux-x64
path: dist/Qlyra-linux-x64.tar.gz
if-no-files-found: error
retention-days: 30
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
- name: Upload macOS DMG artifact
uses: actions/upload-artifact@v4
with:
name: komet-macos
name: qlyra-macos
path: dist/*.dmg
if-no-files-found: error
retention-days: 30
+3 -3
View File
@@ -52,12 +52,12 @@ jobs:
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Komet-windows-x64.zip
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Qlyra-windows-x64.zip
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: komet-windows-x64
path: dist/Komet-windows-x64.zip
name: qlyra-windows-x64
path: dist/Qlyra-windows-x64.zip
if-no-files-found: error
retention-days: 30
+3 -3
View File
@@ -60,17 +60,17 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
- name: Build Android APK
run: flutter build apk --release --flavor komet
run: flutter build apk --release --flavor qlyra
build-ios:
runs-on: macos-latest
+3 -3
View File
@@ -59,17 +59,17 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
- name: Build Android APK
run: flutter build apk --release --flavor komet
run: flutter build apk --release --flavor qlyra
linux:
runs-on: ubuntu-latest
+17 -17
View File
@@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
flavor: [komet, oneme]
flavor: [qlyra, oneme]
steps:
- uses: actions/checkout@v3
with:
@@ -70,12 +70,12 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
@@ -89,12 +89,12 @@ jobs:
run: |
F=${{ matrix.flavor }}
mkdir -p dist
cp build/app/outputs/flutter-apk/app-$F-release.apk dist/Komet-android-$F-universal.apk
cp build/app/outputs/flutter-apk/app-arm64-v8a-$F-release.apk dist/Komet-android-$F-arm64-v8a.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-$F-release.apk dist/Komet-android-$F-armeabi-v7a.apk
cp build/app/outputs/flutter-apk/app-x86_64-$F-release.apk dist/Komet-android-$F-x86_64.apk
cp build/app/outputs/bundle/${F}Release/app-$F-release.aab dist/Komet-android-$F.aab
tar -czf dist/Komet-android-$F-symbols.tar.gz -C build/symbols .
cp build/app/outputs/flutter-apk/app-$F-release.apk dist/Qlyra-android-$F-universal.apk
cp build/app/outputs/flutter-apk/app-arm64-v8a-$F-release.apk dist/Qlyra-android-$F-arm64-v8a.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-$F-release.apk dist/Qlyra-android-$F-armeabi-v7a.apk
cp build/app/outputs/flutter-apk/app-x86_64-$F-release.apk dist/Qlyra-android-$F-x86_64.apk
cp build/app/outputs/bundle/${F}Release/app-$F-release.aab dist/Qlyra-android-$F.aab
tar -czf dist/Qlyra-android-$F-symbols.tar.gz -C build/symbols .
- name: Upload Android artifacts (${{ matrix.flavor }})
uses: actions/upload-artifact@v4
@@ -127,7 +127,7 @@ jobs:
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Komet-windows-x64.zip
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Qlyra-windows-x64.zip
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
@@ -162,7 +162,7 @@ jobs:
- name: Package Linux
run: |
mkdir -p dist
tar -C build/linux/x64/release/bundle -czf dist/Komet-linux-x64.tar.gz .
tar -C build/linux/x64/release/bundle -czf dist/Qlyra-linux-x64.tar.gz .
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
@@ -196,7 +196,7 @@ jobs:
run: |
mkdir -p dist
APP=$(find build/macos/Build/Products/Release -maxdepth 1 -name "*.app" | head -1)
ditto -c -k --keepParent "$APP" dist/Komet-macos.zip
ditto -c -k --keepParent "$APP" dist/Qlyra-macos.zip
- name: Upload macOS artifact
uses: actions/upload-artifact@v4
with:
@@ -230,7 +230,7 @@ jobs:
run: |
mkdir -p dist build/ios/Payload
cp -R build/ios/iphoneos/Runner.app build/ios/Payload/
(cd build/ios && zip -qr ../../dist/Komet-ios-unsigned.ipa Payload)
(cd build/ios && zip -qr ../../dist/Qlyra-ios-unsigned.ipa Payload)
rm -rf build/ios/Payload
- name: Install ldid
run: brew install ldid
@@ -246,9 +246,9 @@ jobs:
<dict>
<key>platform-application</key><true/>
<key>get-task-allow</key><true/>
<key>application-identifier</key><string>ru.komet.app</string>
<key>application-identifier</key><string>ru.qlyra.app</string>
<key>keychain-access-groups</key>
<array><string>ru.komet.app</string></array>
<array><string>ru.qlyra.app</string></array>
<key>com.apple.private.security.no-container</key><true/>
</dict>
</plist>
@@ -271,7 +271,7 @@ jobs:
run: |
mkdir -p dist build/ios/Payload
cp -R build/ios/iphoneos/Runner.app build/ios/Payload/
(cd build/ios && zip -qr ../../dist/Komet-ios-pseudosigned.ipa Payload)
(cd build/ios && zip -qr ../../dist/Qlyra-ios-pseudosigned.ipa Payload)
- name: Upload iOS artifact
uses: actions/upload-artifact@v4
with:
@@ -297,7 +297,7 @@ jobs:
BUILD="${{ github.event.inputs.build_number }}"
BUILD="${BUILD:-$GITHUB_RUN_NUMBER}"
echo "tag=v${BRANCH_VERSION}-dev.${BUILD}" >> "$GITHUB_OUTPUT"
echo "name=Komet ${BRANCH_VERSION}-dev (build ${BUILD})" >> "$GITHUB_OUTPUT"
echo "name=Qlyra ${BRANCH_VERSION}-dev (build ${BUILD})" >> "$GITHUB_OUTPUT"
- name: List artifacts
run: ls -lhR dist
+31 -31
View File
@@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
flavor: [komet, oneme]
flavor: [qlyra, oneme]
steps:
- uses: actions/checkout@v3
with:
@@ -65,12 +65,12 @@ jobs:
echo "KEYSTORE_BASE64 secret not set — release will be debug-signed."
exit 0
fi
echo "$KEYSTORE_BASE64" | base64 -d > android/app/komet-release.jks
echo "$KEYSTORE_BASE64" | base64 -d > android/app/qlyra-release.jks
{
echo "storePassword=$KEYSTORE_PASSWORD"
echo "keyPassword=$KEY_PASSWORD"
echo "keyAlias=$KEY_ALIAS"
echo "storeFile=komet-release.jks"
echo "storeFile=qlyra-release.jks"
} > android/key.properties
echo "Release signing configured."
@@ -84,12 +84,12 @@ jobs:
run: |
F=${{ matrix.flavor }}
mkdir -p dist
cp build/app/outputs/flutter-apk/app-$F-release.apk dist/Komet-android-$F-universal.apk
cp build/app/outputs/flutter-apk/app-arm64-v8a-$F-release.apk dist/Komet-android-$F-arm64-v8a.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-$F-release.apk dist/Komet-android-$F-armeabi-v7a.apk
cp build/app/outputs/flutter-apk/app-x86_64-$F-release.apk dist/Komet-android-$F-x86_64.apk
cp build/app/outputs/bundle/${F}Release/app-$F-release.aab dist/Komet-android-$F.aab
tar -czf dist/Komet-android-$F-symbols.tar.gz -C build/symbols .
cp build/app/outputs/flutter-apk/app-$F-release.apk dist/Qlyra-android-$F-universal.apk
cp build/app/outputs/flutter-apk/app-arm64-v8a-$F-release.apk dist/Qlyra-android-$F-arm64-v8a.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-$F-release.apk dist/Qlyra-android-$F-armeabi-v7a.apk
cp build/app/outputs/flutter-apk/app-x86_64-$F-release.apk dist/Qlyra-android-$F-x86_64.apk
cp build/app/outputs/bundle/${F}Release/app-$F-release.aab dist/Qlyra-android-$F.aab
tar -czf dist/Qlyra-android-$F-symbols.tar.gz -C build/symbols .
- name: Upload Android artifacts (${{ matrix.flavor }})
uses: actions/upload-artifact@v4
@@ -122,7 +122,7 @@ jobs:
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Komet-windows-x64.zip
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath dist/Qlyra-windows-x64.zip
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
@@ -157,7 +157,7 @@ jobs:
- name: Package Linux
run: |
mkdir -p dist
tar -C build/linux/x64/release/bundle -czf dist/Komet-linux-x64.tar.gz .
tar -C build/linux/x64/release/bundle -czf dist/Qlyra-linux-x64.tar.gz .
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
@@ -189,7 +189,7 @@ jobs:
run: |
mkdir -p dist
APP=$(find build/macos/Build/Products/Release -maxdepth 1 -name "*.app" | head -1)
ditto -c -k --keepParent "$APP" dist/Komet-macos.zip
ditto -c -k --keepParent "$APP" dist/Qlyra-macos.zip
- name: Upload macOS artifact
uses: actions/upload-artifact@v4
with:
@@ -233,9 +233,9 @@ jobs:
<dict>
<key>platform-application</key><true/>
<key>get-task-allow</key><true/>
<key>application-identifier</key><string>ru.komet.app</string>
<key>application-identifier</key><string>ru.qlyra.app</string>
<key>keychain-access-groups</key>
<array><string>ru.komet.app</string></array>
<array><string>ru.qlyra.app</string></array>
<key>com.apple.private.security.no-container</key><true/>
</dict>
</plist>
@@ -258,7 +258,7 @@ jobs:
run: |
mkdir -p dist build/ios/Payload
cp -R build/ios/iphoneos/Runner.app build/ios/Payload/
(cd build/ios && zip -qr ../../dist/Komet-ios-pseudosigned.ipa Payload)
(cd build/ios && zip -qr ../../dist/Qlyra-ios-pseudosigned.ipa Payload)
- name: Upload iOS artifact
uses: actions/upload-artifact@v4
with:
@@ -286,7 +286,7 @@ jobs:
run: |
PUBSPEC_VERSION=$(grep '^version:' pubspec.yaml | awk '{print $2}' | cut -d'+' -f1)
echo "tag=v${PUBSPEC_VERSION}+${GITHUB_RUN_NUMBER}" >> "$GITHUB_OUTPUT"
echo "name=Komet ${PUBSPEC_VERSION} (сборка ${GITHUB_RUN_NUMBER})" >> "$GITHUB_OUTPUT"
echo "name=Qlyra ${PUBSPEC_VERSION} (сборка ${GITHUB_RUN_NUMBER})" >> "$GITHUB_OUTPUT"
- name: List artifacts
run: ls -lhR dist
@@ -305,31 +305,31 @@ jobs:
## Какой файл качать
### Android — версия Komet (без push-уведомлений)
- **`Komet-android-komet-arm64-v8a.apk`** — рекомендуется для большинства современных телефонов (64-битный ARM).
- `Komet-android-komet-universal.apk` — универсальный APK, работает везде, но весит больше.
- `Komet-android-komet-armeabi-v7a.apk` — для старых 32-битных устройств.
- `Komet-android-komet-x86_64.apk` — для эмуляторов и редких x86-устройств.
- `Komet-android-komet.aab` — App Bundle для публикации в Google Play (не для ручной установки).
### Android — версия Qlyra (без push-уведомлений)
- **`Qlyra-android-qlyra-arm64-v8a.apk`** — рекомендуется для большинства современных телефонов (64-битный ARM).
- `Qlyra-android-qlyra-universal.apk` — универсальный APK, работает везде, но весит больше.
- `Qlyra-android-qlyra-armeabi-v7a.apk` — для старых 32-битных устройств.
- `Qlyra-android-qlyra-x86_64.apk` — для эмуляторов и редких x86-устройств.
- `Qlyra-android-qlyra.aab` — App Bundle для публикации в Google Play (не для ручной установки).
### Android — версия OneMe (с push-уведомлениями через Firebase)
- **`Komet-android-oneme-arm64-v8a.apk`** — рекомендуется для большинства современных телефонов.
- `Komet-android-oneme-universal.apk` — универсальный APK.
- `Komet-android-oneme-armeabi-v7a.apk` — для старых 32-битных устройств.
- `Komet-android-oneme-x86_64.apk` — для эмуляторов и x86-устройств.
- `Komet-android-oneme.aab` — App Bundle для Google Play.
- **`Qlyra-android-oneme-arm64-v8a.apk`** — рекомендуется для большинства современных телефонов.
- `Qlyra-android-oneme-universal.apk` — универсальный APK.
- `Qlyra-android-oneme-armeabi-v7a.apk` — для старых 32-битных устройств.
- `Qlyra-android-oneme-x86_64.apk` — для эмуляторов и x86-устройств.
- `Qlyra-android-oneme.aab` — App Bundle для Google Play.
### Windows
- **`Komet-windows-x64.zip`** — портативная сборка для Windows 10/11 (x64). Распаковать и запустить `Komet.exe`.
- **`Qlyra-windows-x64.zip`** — портативная сборка для Windows 10/11 (x64). Распаковать и запустить `Qlyra.exe`.
### Linux
- **`Komet-linux-x64.tar.gz`** — сборка для 64-битного Linux. Требуются `libgtk-3`, `libsecret-1`, `libjsoncpp`. Распаковать и запустить бинарник.
- **`Qlyra-linux-x64.tar.gz`** — сборка для 64-битного Linux. Требуются `libgtk-3`, `libsecret-1`, `libjsoncpp`. Распаковать и запустить бинарник.
### macOS
- **`Komet-macos.zip`** — `.app` для macOS. Распаковать и перетащить в `/Applications`. Приложение не нотаризовано — при первом запуске разрешите через «Системные настройки → Защита и безопасность».
- **`Qlyra-macos.zip`** — `.app` для macOS. Распаковать и перетащить в `/Applications`. Приложение не нотаризовано — при первом запуске разрешите через «Системные настройки → Защита и безопасность».
### iOS
- **`Komet-ios-pseudosigned.ipa`** — IPA с псевдо-подписью (ldid).
- **`Qlyra-ios-pseudosigned.ipa`** — IPA с псевдо-подписью (ldid).
⚠️ Не устанавливается через App Store. Подходит для:
- jailbreak (Filza, rootless),
- TrollStore,
+1 -4
View File
@@ -136,7 +136,7 @@ agents.md
.env
.env.*
# Локальные дампы трафика и скрипты анализа (содержат секреты)
komet.txt
qlyra.txt
original_app.txt
fingerprint.py
PCAPdroid_*.txt
@@ -149,8 +149,5 @@ maxtun/
turnprobe/
test/live_server_probe_test.dart
# local kolibri development: point the plugin at third_party/kolibri and the
# Rust core at third_party/kolibri/kolibri-net instead of the published ones
pubspec_overrides.yaml
.cargo/
third_party/kolibri/
-4
View File
@@ -1,4 +0,0 @@
{
"cmake.sourceDirectory": "/run/media/invisedivine/Drive/! My projects/Komet/linux/runner",
"kiroAgent.configureMCP": "Disabled"
}
-8
View File
@@ -1,8 +0,0 @@
Не оставляй комментарии в код
Старайся писать чистый код
Лучше качество чем количество
Когда при исправления какой то ошибки/добавление новой возникает ситуация 50/50 где можно выбрать починить сейчас но костылём, или чинить долго, упорно, может даже вообще не починить и переписать пол приложения - выбирай долго и упорно.
ВМЕСТО СНЕКБАРОВ ИСПОЛЬЗУЙ НАШИ КАСТОМНЫЕ УВЕДОМЛЕНИЕ showCustomNotification(context, 'текст')
Never leave real data in test files, including existing message contents or real IDs captured from requests. Use synthetic fixtures instead.
Не пытайся собирать APK/AAB (flutter build apk, flutter build appbundle, gradle assemble) — сборку запускает пользователь, тебе достаточно flutter analyze
Если делаешь кнопку, где иконка переключается перечёркнутая/неперечёркнутая (вспышка, микрофон, звук, уведомления) — она должна анимироваться lottie-иконкой, а не подменяться мгновенно: добавь спеку в SLASH_SPECS в tool/make_morph_icons.py (fill=1.0, если кнопка рисует Icon(..., fill: 1)), прогони python3 tool/make_morph_icons.py и выводи через LottieSlashIcon. Ассеты в assets/lottie/ руками не правь — только через генератор.
+8 -8
View File
@@ -4,20 +4,20 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project
Komet is a cross-platform Flutter messaging client (Android, iOS, macOS, Windows, Linux, Web) that communicates via a custom packet-based protocol with MessagePack serialization and Zstd compression.
Qlyra is a cross-platform Flutter messaging client (Android, iOS, macOS, Windows, Linux, Web) that communicates via a custom packet-based protocol with MessagePack serialization and Zstd compression.
## Commands
```bash
flutter pub get # install dependencies
flutter analyze # lint / static analysis
flutter run # run on connected device (default: komet flavor)
flutter run # run on connected device (default: qlyra flavor)
flutter run --flavor oneme -t lib/main.dart # run oneme flavor (FCM)
# Android builds (release builds use obfuscation; keep symbols to de-obfuscate crashes)
flutter build apk --release --flavor komet --obfuscate --split-debug-info=build/symbols
flutter build apk --release --split-per-abi --flavor komet --obfuscate --split-debug-info=build/symbols
flutter build appbundle --release --flavor komet --obfuscate --split-debug-info=build/symbols
flutter build apk --release --flavor qlyra --obfuscate --split-debug-info=build/symbols
flutter build apk --release --split-per-abi --flavor qlyra --obfuscate --split-debug-info=build/symbols
flutter build appbundle --release --flavor qlyra --obfuscate --split-debug-info=build/symbols
# Other platforms
flutter build ios --release --no-codesign
@@ -35,10 +35,10 @@ Android builds require **Java 17**. Gradle memory is configured to `-Xmx4096m`.
| Flavor | App ID | Notes |
|--------|--------|-------|
| `komet` | `ru.komet.app` | Default, no FCM |
| `qlyra` | `ru.qlyra.app` | Default, no FCM |
| `oneme` | `ru.oneme.app` | FCM push notifications via Firebase |
Flavor-specific Android resources live in `android/app/src/komet/` and `android/app/src/oneme/`.
Flavor-specific Android resources live in `android/app/src/qlyra/` and `android/app/src/oneme/`.
## Architecture
@@ -97,5 +97,5 @@ Four GitHub Actions workflows in `.github/workflows/`:
- `flutter-dev.yml` — PR lint + Android build for dev branch
- `flutter-main.yml` — PR lint + all-platform builds for main branch
- `build-android.yml` — production APKs + AAB (`komet` flavor), triggered on push to main
- `build-android.yml` — production APKs + AAB (`qlyra` flavor), triggered on push to main
- `build-android-fcm.yml` — production APKs + AAB (`oneme` flavor with FCM), triggered on push to main
+8 -11
View File
@@ -1,19 +1,16 @@
> [!IMPORTANT]
> Потерялись? Возможно вы ищите старую версию Komet. Она расположена [здесь](https://github.com/KometTeam/KometOld).
---
<img src="assets/qlyra.png" width="100" alt="Qlyra Logo">
<img src="assets/komet.png" width="100" alt="Komet Logo">
# Qlyra
# Komet
Альтернативный FOSS клиент для мессенджера MAX
Кроссплатформенный клиент для мессенджера MAX.
## Установка
[Последний релиз](https://github.com/KometTeam/Komet/releases/latest) / [Telegram Канал](https://t.me/TeamKomet)
## Android
Основной вариант приложения использует идентификатор `ru.qlyra.app` и flavor `qlyra`.
## Сборка из исходного кода
```console
$ flutter build [windows|linux] [--release]
$ flutter build apk --release --flavor qlyra
```
## Хотите помочь?
Нашли ошибку и сами её исправили? Сделайте Pull-Request.<br/>
+1 -1
View File
@@ -11,6 +11,6 @@ GeneratedPluginRegistrant.java
# See https://flutter.dev/to/reference-keystore
key.properties
app/key.properties
app/komet-release.jks
app/qlyra-release.jks
**/*.keystore
**/*.jks
+4 -4
View File
@@ -17,7 +17,7 @@ if (hasReleaseSigning) {
}
android {
namespace = "ru.komet.app"
namespace = "ru.qlyra.app"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -32,7 +32,7 @@ android {
}
defaultConfig {
applicationId = "ru.komet.app"
applicationId = "ru.qlyra.app"
minSdk = maxOf(flutter.minSdkVersion, 23)
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
@@ -54,10 +54,10 @@ android {
flavorDimensions += "distribution"
productFlavors {
create("komet") {
create("qlyra") {
dimension = "distribution"
isDefault = true
applicationId = "ru.komet.app"
applicationId = "ru.qlyra.app"
}
create("oneme") {
dimension = "distribution"
+11 -20
View File
@@ -33,15 +33,15 @@
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
<application
android:label="Komet"
android:label="Qlyra"
android:name="${applicationName}"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher">
<activity
android:name="ru.komet.app.MainActivity"
android:name="ru.qlyra.app.MainActivity"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:label="Komet"
android:label="Qlyra"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
@@ -69,20 +69,11 @@
<data android:scheme="http" android:host="max.ru"/>
<data android:scheme="http" android:host="www.max.ru"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https" android:host="komet.pw"/>
<data android:scheme="https" android:host="www.komet.pw"/>
<data android:path="/export-logs"/>
<data android:path="/export-logs/"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="komet"/>
<data android:scheme="qlyra"/>
<data android:scheme="max"/>
</intent-filter>
<intent-filter android:label="@string/share_target_label">
@@ -104,12 +95,12 @@
</intent-filter>
</activity>
<activity-alias
android:name="ru.komet.app.MinimalIcon"
android:name="ru.qlyra.app.MinimalIcon"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_minimal"
android:label="Komet"
android:targetActivity="ru.komet.app.MainActivity">
android:icon="@mipmap/ic_launcher"
android:label="Qlyra"
android:targetActivity="ru.qlyra.app.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -130,10 +121,10 @@
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/komet_nfc_apdu"/>
android:resource="@xml/qlyra_nfc_apdu"/>
</service>
<service
android:name=".KometFcmService"
android:name=".QlyraFcmService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
@@ -175,7 +166,7 @@
android:value="2" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="komet_messages" />
android:value="qlyra_messages" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
+1 -1
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(komet_rlottie LANGUAGES C CXX ASM)
project(qlyra_rlottie LANGUAGES C CXX ASM)
add_subdirectory(
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../third_party/rlottie_build"
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.app.Service
import android.content.Context
@@ -20,9 +20,9 @@ object CallState {
class CallForegroundService : Service() {
companion object {
const val ACTION_START = "ru.komet.app.CALL_ONGOING_START"
const val ACTION_STOP = "ru.komet.app.CALL_ONGOING_STOP"
const val ACTION_SCREEN_SHARE = "ru.komet.app.CALL_SCREEN_SHARE"
const val ACTION_START = "ru.qlyra.app.CALL_ONGOING_START"
const val ACTION_STOP = "ru.qlyra.app.CALL_ONGOING_STOP"
const val ACTION_SCREEN_SHARE = "ru.qlyra.app.CALL_SCREEN_SHARE"
const val EXTRA_SCREEN_SHARE = "screenShare"
const val ONGOING_ID = 424243
@@ -46,7 +46,7 @@ class CallForegroundService : Service() {
ctx.startService(intent)
}
} catch (e: Exception) {
Log.w("KometFcm", "screen share FGS update failed: ${e.message}")
Log.w("QlyraFcm", "screen share FGS update failed: ${e.message}")
}
}
@@ -63,7 +63,7 @@ class CallForegroundService : Service() {
ctx.startService(intent)
}
} catch (e: Exception) {
Log.w("KometFcm", "ongoing FGS start failed: ${e.message}")
Log.w("QlyraFcm", "ongoing FGS start failed: ${e.message}")
}
}
@@ -160,7 +160,7 @@ class CallForegroundService : Service() {
startForeground(ONGOING_ID, notif)
}
} catch (e: Exception) {
Log.w("KometFcm", "startForeground failed: ${e.message}")
Log.w("QlyraFcm", "startForeground failed: ${e.message}")
stopSelf()
}
}
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.app.NotificationChannel
import android.app.NotificationManager
@@ -46,21 +46,21 @@ object CallEvents {
}
object CallConst {
const val CHANNEL_ID = "komet_calls"
const val CHANNEL_ID = "qlyra_calls"
const val CHANNEL_NAME = "Звонки"
const val NOTIF_ID = 424242
const val ACCENT = 0xFF7C6BF0.toInt()
const val EXTRA_CALL = "komet_call"
const val EXTRA_ACTION = "komet_call_action"
const val EXTRA_DECLINE_PAYLOAD = "komet_decline_payload"
const val EXTRA_NOTIF_ID = "komet_notif_id"
const val EXTRA_CALLER = "komet_caller"
const val EXTRA_CALL = "qlyra_call"
const val EXTRA_ACTION = "qlyra_call_action"
const val EXTRA_DECLINE_PAYLOAD = "qlyra_decline_payload"
const val EXTRA_NOTIF_ID = "qlyra_notif_id"
const val EXTRA_CALLER = "qlyra_caller"
const val ACTION_RING = "ring"
const val ACTION_ANSWER = "answer"
const val ACTION_DECLINE = "ru.komet.app.CALL_DECLINE"
const val ACTION_HANGUP = "ru.komet.app.CALL_HANGUP"
const val ACTION_DECLINE = "ru.qlyra.app.CALL_DECLINE"
const val ACTION_HANGUP = "ru.qlyra.app.CALL_HANGUP"
const val FLN_RECEIVER =
"com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver"
@@ -72,7 +72,7 @@ object CallNotifier {
fun showIncoming(ctx: Context, data: Map<String, String>) {
if (AppState.resumed) {
Log.d("KometFcm", "call push suppressed (app foreground)")
Log.d("QlyraFcm", "call push suppressed (app foreground)")
return
}
val name = data["userName"] ?: data["title"] ?: "Неизвестный"
@@ -82,7 +82,7 @@ object CallNotifier {
val account = data["c"] ?: ""
val callJson = JSONObject(data as Map<*, *>).toString()
Log.d("KometFcm", "showIncoming caller=$callerId conv=$conversationId keys=${data.keys}")
Log.d("QlyraFcm", "showIncoming caller=$callerId conv=$conversationId keys=${data.keys}")
ensureChannel(ctx)
@@ -117,7 +117,7 @@ object CallNotifier {
}
fun finishCall(ctx: Context, data: Map<String, String>) {
Log.d("KometFcm", "finishCall keys=${data.keys}")
Log.d("QlyraFcm", "finishCall keys=${data.keys}")
CallRinger.stop()
NotificationManagerCompat.from(ctx).cancel(CallConst.NOTIF_ID)
CallEvents.emit("ended")
@@ -208,7 +208,7 @@ object CallRinger {
activeConversationId = conversationId
val power = ctx.getSystemService(Context.POWER_SERVICE) as PowerManager
wakeLock = power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "komet:call").apply {
wakeLock = power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "qlyra:call").apply {
setReferenceCounted(false)
acquire(60_000L)
}
@@ -271,7 +271,7 @@ object CallRinger {
rt.play()
ringtone = rt
} catch (e: Exception) {
Log.w("KometFcm", "ringtone failed: ${e.message}")
Log.w("QlyraFcm", "ringtone failed: ${e.message}")
}
}
@@ -288,7 +288,7 @@ object CallRinger {
}
vibrator = vib
} catch (e: Exception) {
Log.w("KometFcm", "vibrate failed: ${e.message}")
Log.w("QlyraFcm", "vibrate failed: ${e.message}")
}
}
}
@@ -315,7 +315,7 @@ class CallActionReceiver : BroadcastReceiver() {
try {
ctx.sendBroadcast(fln)
} catch (e: Exception) {
Log.w("KometFcm", "decline broadcast failed: ${e.message}")
Log.w("QlyraFcm", "decline broadcast failed: ${e.message}")
}
}
}
@@ -1,10 +1,10 @@
package ru.komet.app
package ru.qlyra.app
import android.content.Intent
import io.flutter.plugin.common.EventChannel
object ChatNotifications {
const val EXTRA_CHAT = "komet_chat"
const val EXTRA_CHAT = "qlyra_chat"
@Volatile
var activeChatId: Long = 0L
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.Manifest
import android.app.Activity
@@ -20,7 +20,7 @@ import io.flutter.plugin.common.MethodChannel
import java.util.concurrent.Executors
object FkmChannel {
private const val NAME = "ru.komet.app/fkm"
private const val NAME = "ru.qlyra.app/fkm"
const val NOTIF_PERMS_REQUEST = 7713
private val main = Handler(Looper.getMainLooper())
@@ -117,7 +117,7 @@ object FkmChannel {
val data = call.argument<Map<String, String>>("data") ?: return false
worker.execute {
try {
KometNotifier(ctx).handle(data)
QlyraNotifier(ctx).handle(data)
FkmState.countDelivered(ctx)
FkmService.refresh(ctx)
} catch (e: Exception) {
@@ -132,12 +132,12 @@ object FkmChannel {
ctx: Context,
call: MethodCall,
tag: String,
action: (KometNotifier, Map<String, String>) -> Unit,
action: (QlyraNotifier, Map<String, String>) -> Unit,
): Boolean {
val data = call.argument<Map<String, String>>("data") ?: return false
worker.execute {
try {
action(KometNotifier(ctx), data)
action(QlyraNotifier(ctx), data)
} catch (e: Exception) {
Log.w("Fkm", "$tag failed: ${e.message}")
}
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.app.Notification
import android.app.NotificationChannel
@@ -15,7 +15,7 @@ import android.util.Log
import androidx.core.app.NotificationCompat
object FkmState {
private const val PREFS = "komet_fkm"
private const val PREFS = "qlyra_fkm"
private const val KEY_ENABLED = "enabled"
private const val KEY_DELIVERED = "delivered"
@@ -60,7 +60,7 @@ object FkmState {
}
object FkmNotification {
const val CHANNEL_ID = "komet_fkm"
const val CHANNEL_ID = "qlyra_fkm"
const val NOTIFICATION_ID = 424244
fun build(ctx: Context): Notification {
@@ -228,7 +228,7 @@ class FkmService : Service() {
class FkmDisableReceiver : BroadcastReceiver() {
companion object {
const val ACTION_DISABLE = "ru.komet.app.FKM_DISABLE"
const val ACTION_DISABLE = "ru.qlyra.app.FKM_DISABLE"
}
override fun onReceive(ctx: Context, intent: Intent) {
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.Manifest
import android.app.KeyguardManager
@@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicBoolean
class MainActivity : FlutterActivity() {
private val channelName = "ru.komet.app/vpn_bypass"
private val channelName = "ru.qlyra.app/vpn_bypass"
private val iconPackage = MainActivity::class.java.name.substringBeforeLast('.')
private val iconComponents = mapOf(
"MainActivity" to "$iconPackage.MainActivity",
@@ -89,7 +89,7 @@ class MainActivity : FlutterActivity() {
const val LOG_TAG = "VpnBypass"
const val SHARE_TAG = "ShareIntake"
const val NFC_TAG = "NfcExchange"
const val KEEP_ENGINE_ID = "komet_keep_engine"
const val KEEP_ENGINE_ID = "qlyra_keep_engine"
const val NFC_PHASE_MIN_MS = 350L
const val NFC_PHASE_JITTER_MS = 400
const val BLE_PERMS_REQUEST = 7711
@@ -126,7 +126,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/nfc",
"ru.qlyra.app/nfc",
).setMethodCallHandler { call, result ->
when (call.method) {
"status" -> result.success(nfcStatus())
@@ -150,7 +150,7 @@ class MainActivity : FlutterActivity() {
EventChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/nfc_events",
"ru.qlyra.app/nfc_events",
).setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
nfcEvents = events
@@ -175,7 +175,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/app_icon",
"ru.qlyra.app/app_icon",
).setMethodCallHandler { call, result ->
when (call.method) {
"setAppIcon" -> {
@@ -197,7 +197,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/upload_service",
"ru.qlyra.app/upload_service",
).setMethodCallHandler { call, result ->
val ctx = this
fun uploadIntent(call: MethodCall, action: String) =
@@ -248,7 +248,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/video_note",
"ru.qlyra.app/video_note",
).setMethodCallHandler { call, result ->
when (call.method) {
"permission" -> requestNotePermissions(result)
@@ -287,7 +287,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/video",
"ru.qlyra.app/video",
).setMethodCallHandler { call, result ->
when (call.method) {
"cropSquare" -> {
@@ -332,7 +332,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/calls",
"ru.qlyra.app/calls",
).setMethodCallHandler { call, result ->
when (call.method) {
"consumeInitialCall" -> {
@@ -393,7 +393,7 @@ class MainActivity : FlutterActivity() {
),
)
} catch (e: Exception) {
Log.w("KometFcm", "open FSI settings failed: ${e.message}")
Log.w("QlyraFcm", "open FSI settings failed: ${e.message}")
}
}
result.success(null)
@@ -404,7 +404,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/screen",
"ru.qlyra.app/screen",
).setMethodCallHandler { call, result ->
when (call.method) {
"setKeepAwake" -> {
@@ -417,7 +417,7 @@ class MainActivity : FlutterActivity() {
EventChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/calls_events",
"ru.qlyra.app/calls_events",
).setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
CallEvents.sink = events
@@ -430,7 +430,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/notifications",
"ru.qlyra.app/notifications",
).setMethodCallHandler { call, result ->
when (call.method) {
"consumeInitialChat" -> {
@@ -453,7 +453,7 @@ class MainActivity : FlutterActivity() {
EventChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/notification_events",
"ru.qlyra.app/notification_events",
).setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
ChatNotifications.sink = events
@@ -466,7 +466,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/share",
"ru.qlyra.app/share",
).setMethodCallHandler { call, result ->
when (call.method) {
"consumeInitialShare" -> {
@@ -501,7 +501,7 @@ class MainActivity : FlutterActivity() {
EventChannel(
flutterEngine.dartExecutor.binaryMessenger,
"ru.komet.app/share_events",
"ru.qlyra.app/share_events",
).setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
ShareIntake.sink = events
@@ -965,7 +965,7 @@ class MainActivity : FlutterActivity() {
override fun onDestroy() {
shareExecutor.shutdown()
if (keepEngineAlive() && isFinishing) {
Log.d("KometFcm", "task removed, caching engine (call=${CallState.inCall} fkm=${FkmState.enabled})")
Log.d("QlyraFcm", "task removed, caching engine (call=${CallState.inCall} fkm=${FkmState.enabled})")
flutterEngine?.let { FlutterEngineCache.getInstance().put(KEEP_ENGINE_ID, it) }
}
super.onDestroy()
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
object NfcExchange {
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.nfc.cardemulation.HostApduService
import android.os.Bundle
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.content.Context
import android.graphics.Bitmap
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.app.NotificationChannel
import android.app.NotificationManager
@@ -26,29 +26,29 @@ import com.google.firebase.messaging.RemoteMessage
import org.json.JSONArray
import org.json.JSONObject
class KometFcmService : FirebaseMessagingService() {
class QlyraFcmService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
val data = message.data
Log.d("KometFcm", "onMessageReceived type=${data["type"]} keys=${data.keys}")
Log.d("QlyraFcm", "onMessageReceived type=${data["type"]} keys=${data.keys}")
if (data.isEmpty()) return
val type = data["type"]
FkmState.restore(applicationContext)
if (FkmState.enabled && type != "InboundCall" && type != "CallFinished") {
Log.d("KometFcm", "message push dropped: FKM handles messages")
Log.d("QlyraFcm", "message push dropped: FKM handles messages")
return
}
KometNotifier(applicationContext).handle(data)
QlyraNotifier(applicationContext).handle(data)
}
}
class KometNotifier(private val ctx: Context) {
class QlyraNotifier(private val ctx: Context) {
companion object {
private const val CHANNEL_ID = "komet_messages"
private const val CHANNEL_ID = "qlyra_messages"
private const val CHANNEL_NAME = "Сообщения"
private const val GROUP_KEY = "komet_messages_group"
private const val GROUP_KEY = "qlyra_messages_group"
private const val SUMMARY_ID = 424200
private const val PREFS = "komet_push"
private const val PREFS = "qlyra_push"
private const val FLN_RECEIVER =
"com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver"
private const val FLN_ACTION_TAPPED =
@@ -336,7 +336,7 @@ class KometNotifier(private val ctx: Context) {
.setShowWhen(true)
.setNumber(entries.size)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.setContentTitle("Komet")
.setContentTitle("Qlyra")
.setContentText(boldLine(newest.first, newest.second))
.setStyle(inbox)
.build()
@@ -399,7 +399,7 @@ class KometNotifier(private val ctx: Context) {
.build()
ShortcutManagerCompat.pushDynamicShortcut(ctx, shortcut)
} catch (e: Exception) {
Log.w("KometFcm", "shortcut push failed: $e")
Log.w("QlyraFcm", "shortcut push failed: $e")
}
}
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.content.ContentResolver
import android.content.Context
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.app.*
import android.content.Intent
@@ -11,11 +11,11 @@ import androidx.core.app.NotificationCompat
class UploadForegroundService : Service() {
companion object {
const val CHANNEL_ID = "komet_upload"
const val CHANNEL_ID = "qlyra_upload"
const val NOTIFICATION_ID = 9001
const val ACTION_START = "ru.komet.app.UPLOAD_START"
const val ACTION_UPDATE = "ru.komet.app.UPLOAD_UPDATE"
const val ACTION_STOP = "ru.komet.app.UPLOAD_STOP"
const val ACTION_START = "ru.qlyra.app.UPLOAD_START"
const val ACTION_UPDATE = "ru.qlyra.app.UPLOAD_UPDATE"
const val ACTION_STOP = "ru.qlyra.app.UPLOAD_STOP"
const val EXTRA_TITLE = "title"
const val EXTRA_BODY = "body"
const val EXTRA_PROGRESS = "progress"
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.content.Context
import android.graphics.Bitmap
@@ -1,4 +1,4 @@
package ru.komet.app
package ru.qlyra.app
import android.Manifest
import android.content.Context
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 49 KiB

@@ -2,7 +2,7 @@
<string name="upload_channel_name">Отправка медиа</string>
<string name="fkm_channel_name">Сервис уведомлений</string>
<string name="fkm_channel_description">Держит фоновое соединение с сервером</string>
<string name="fkm_title">Komet · сервис уведомлений</string>
<string name="fkm_title">Qlyra · сервис уведомлений</string>
<string name="fkm_status_active">Соединение активно</string>
<string name="fkm_status_inactive">Соединение не активно</string>
<string name="fkm_status_line">%1$s · принято %2$d</string>
+3 -3
View File
@@ -1,10 +1,10 @@
<resources>
<string name="nfc_service_description">Komet contact exchange</string>
<string name="nfc_aid_group_description">Komet contact exchange</string>
<string name="nfc_service_description">Qlyra contact exchange</string>
<string name="nfc_aid_group_description">Qlyra contact exchange</string>
<string name="upload_channel_name">Sending media</string>
<string name="fkm_channel_name">Notification service</string>
<string name="fkm_channel_description">Keeps the background connection to the server alive</string>
<string name="fkm_title">Komet · notification service</string>
<string name="fkm_title">Qlyra · notification service</string>
<string name="fkm_status_active">Connection active</string>
<string name="fkm_status_inactive">Connection inactive</string>
<string name="fkm_status_line">%1$s · %2$d delivered</string>
@@ -9,7 +9,7 @@
"client_info": {
"mobilesdk_app_id": "1:659634599081:android:00000000000000000000ab",
"android_client_info": {
"package_name": "ru.komet.app"
"package_name": "ru.qlyra.app"
}
},
"oauth_client": [],
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

@@ -15,7 +15,7 @@
<rect width="1440" height="2280" fill="#F8F4FE"/>
<g id="header">
<text x="64" y="84" class="title" fill="#1B1B21">Komet — Design System</text>
<text x="64" y="84" class="title" fill="#1B1B21">Qlyra — Design System</text>
<text x="64" y="112" class="small" fill="#46464F">Seed #C1C4FF · Material 3 Expressive · Inter</text>
</g>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+2 -2
View File
@@ -7,7 +7,7 @@ ENV['COCOAPODS_DISABLE_STATS'] = 'true'
require 'json'
# Firebase is Android-only: FCM is used solely by the `oneme` flavor, and on
# iOS there is a single `ru.komet.app` bundle that never initialises push.
# iOS there is a single `ru.qlyra.app` bundle that never initialises push.
# Keep the Firebase SDK out of the iOS build entirely so iOS is not forced up
# to the iOS 15 deployment target that firebase_core's podspec requires.
FIREBASE_IOS_PLUGINS = %w[firebase_core firebase_messaging].freeze
@@ -79,7 +79,7 @@ end
# xcframeworks into the pod target's own build dir, so for Runner that variable
# expands to a file nothing ever produces and Xcode fails on the missing input.
OPUS_XCFRAMEWORK = 'ogg_opus_player/darwin/Frameworks/libopus.xcframework'.freeze
OPUS_LIB_VAR = 'KOMET_OPUS_LIB'.freeze
OPUS_LIB_VAR = 'QLYRA_OPUS_LIB'.freeze
OPUS_FORCE_LOAD = %(-force_load "$(#{OPUS_LIB_VAR})").freeze
OPUS_XCFRAMEWORK_DIR =
File.expand_path(File.join('.symlinks', 'plugins', OPUS_XCFRAMEWORK), __dir__).freeze
+18 -18
View File
@@ -12,9 +12,9 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4B1A4BBCD56B3CE42AD0A480 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 789A1AEF2F4FF7DEED202476 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
AA11BB22CC33DD44EE550101 /* KometVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550001 /* KometVideo.swift */; };
AA11BB22CC33DD44EE550102 /* KometVideoNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550002 /* KometVideoNote.swift */; };
AA11BB22CC33DD44EE550103 /* KometNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550003 /* KometNotifications.swift */; };
AA11BB22CC33DD44EE550101 /* QlyraVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550001 /* QlyraVideo.swift */; };
AA11BB22CC33DD44EE550102 /* QlyraVideoNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550002 /* QlyraVideoNote.swift */; };
AA11BB22CC33DD44EE550103 /* QlyraNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11BB22CC33DD44EE550003 /* QlyraNotifications.swift */; };
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 */; };
@@ -59,9 +59,9 @@
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550001 /* KometVideo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KometVideo.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550002 /* KometVideoNote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KometVideoNote.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550003 /* KometNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KometNotifications.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550001 /* QlyraVideo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QlyraVideo.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550002 /* QlyraVideoNote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QlyraVideoNote.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550003 /* QlyraNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QlyraNotifications.swift; sourceTree = "<group>"; };
AA11BB22CC33DD44EE550004 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
782E66FE4E292DCFD0D1B7D2 /* 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 = "<group>"; };
789A1AEF2F4FF7DEED202476 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -164,9 +164,9 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
AA11BB22CC33DD44EE550001 /* KometVideo.swift */,
AA11BB22CC33DD44EE550002 /* KometVideoNote.swift */,
AA11BB22CC33DD44EE550003 /* KometNotifications.swift */,
AA11BB22CC33DD44EE550001 /* QlyraVideo.swift */,
AA11BB22CC33DD44EE550002 /* QlyraVideoNote.swift */,
AA11BB22CC33DD44EE550003 /* QlyraNotifications.swift */,
AA11BB22CC33DD44EE550004 /* Runner.entitlements */,
);
path = Runner;
@@ -407,9 +407,9 @@
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
AA11BB22CC33DD44EE550101 /* KometVideo.swift in Sources */,
AA11BB22CC33DD44EE550102 /* KometVideoNote.swift in Sources */,
AA11BB22CC33DD44EE550103 /* KometNotifications.swift in Sources */,
AA11BB22CC33DD44EE550101 /* QlyraVideo.swift in Sources */,
AA11BB22CC33DD44EE550102 /* QlyraVideoNote.swift in Sources */,
AA11BB22CC33DD44EE550103 /* QlyraNotifications.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -510,7 +510,7 @@
"@executable_path/Frameworks",
);
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -527,7 +527,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -545,7 +545,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -561,7 +561,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -693,7 +693,7 @@
"@executable_path/Frameworks",
);
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -716,7 +716,7 @@
"@executable_path/Frameworks",
);
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
PRODUCT_BUNDLE_IDENTIFIER = ru.komet.app;
PRODUCT_BUNDLE_IDENTIFIER = ru.qlyra.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
+18 -18
View File
@@ -1,7 +1,7 @@
import Flutter
import UIKit
final class KometStreamHandler: NSObject, FlutterStreamHandler {
final class QlyraStreamHandler: NSObject, FlutterStreamHandler {
private let onSink: (FlutterEventSink?) -> Void
init(onSink: @escaping (FlutterEventSink?) -> Void) {
@@ -26,15 +26,15 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
@objc class AppDelegate: FlutterAppDelegate {
private var channels: [FlutterMethodChannel] = []
private var eventChannels: [FlutterEventChannel] = []
private var streamHandlers: [KometStreamHandler] = []
private var videoNote: KometVideoNote?
private var streamHandlers: [QlyraStreamHandler] = []
private var videoNote: QlyraVideoNote?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
KometNotifications.shared.start()
QlyraNotifications.shared.start()
if let controller = window?.rootViewController as? FlutterViewController {
let messenger = controller.binaryMessenger
@@ -57,7 +57,7 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
private func events(_ name: String, _ messenger: FlutterBinaryMessenger,
_ onSink: @escaping (FlutterEventSink?) -> Void) {
let handler = KometStreamHandler(onSink: onSink)
let handler = QlyraStreamHandler(onSink: onSink)
let channel = FlutterEventChannel(name: name, binaryMessenger: messenger)
channel.setStreamHandler(handler)
streamHandlers.append(handler)
@@ -65,7 +65,7 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
}
private func registerAppIcon(_ messenger: FlutterBinaryMessenger) {
method("ru.komet.app/app_icon", messenger) { call, result in
method("ru.qlyra.app/app_icon", messenger) { call, result in
switch call.method {
case "getAppIcon":
result(UIApplication.shared.alternateIconName)
@@ -100,23 +100,23 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
}
private func registerVideo(_ messenger: FlutterBinaryMessenger) {
method("ru.komet.app/video", messenger) { call, result in
KometVideo.shared.handle(call, result: result)
method("ru.qlyra.app/video", messenger) { call, result in
QlyraVideo.shared.handle(call, result: result)
}
}
private func registerVideoNote(_ messenger: FlutterBinaryMessenger) {
guard let textures = registrar(forPlugin: "KometVideoNote")?.textures() else { return }
guard let textures = registrar(forPlugin: "QlyraVideoNote")?.textures() else { return }
method("ru.komet.app/video_note", messenger) { [weak self] call, result in
method("ru.qlyra.app/video_note", messenger) { [weak self] call, result in
guard let self = self else { return }
switch call.method {
case "permission":
KometVideoNote.requestPermission(result)
QlyraVideoNote.requestPermission(result)
case "init":
let args = call.arguments as? [String: Any] ?? [:]
self.videoNote?.dispose()
let recorder = KometVideoNote(registry: textures)
let recorder = QlyraVideoNote(registry: textures)
self.videoNote = recorder
recorder.initialize(
front: (args["front"] as? NSNumber)?.boolValue ?? true,
@@ -143,7 +143,7 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
}
private func withRecorder(_ result: @escaping FlutterResult,
_ body: (KometVideoNote) -> Void) {
_ body: (QlyraVideoNote) -> Void) {
guard let recorder = videoNote else {
result(FlutterError(code: "NOT_READY", message: "recorder not initialized", details: nil))
return
@@ -152,7 +152,7 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
}
private func registerScreen(_ messenger: FlutterBinaryMessenger) {
method("ru.komet.app/screen", messenger) { call, result in
method("ru.qlyra.app/screen", messenger) { call, result in
switch call.method {
case "setKeepAwake":
let enabled = ((call.arguments as? [String: Any])?["enabled"] as? NSNumber)?.boolValue ?? false
@@ -167,11 +167,11 @@ final class KometStreamHandler: NSObject, FlutterStreamHandler {
}
private func registerNotifications(_ messenger: FlutterBinaryMessenger) {
method("ru.komet.app/notifications", messenger) { call, result in
KometNotifications.shared.handle(call, result: result)
method("ru.qlyra.app/notifications", messenger) { call, result in
QlyraNotifications.shared.handle(call, result: result)
}
events("ru.komet.app/notification_events", messenger) { sink in
KometNotifications.shared.attach(sink)
events("ru.qlyra.app/notification_events", messenger) { sink in
QlyraNotifications.shared.attach(sink)
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 797 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 32 KiB

+4 -4
View File
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Komet</string>
<string>Qlyra</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Komet</string>
<string>Qlyra</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
@@ -76,10 +76,10 @@
<array>
<dict>
<key>CFBundleURLName</key>
<string>ru.komet.app</string>
<string>ru.qlyra.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>komet</string>
<string>qlyra</string>
<string>max</string>
</array>
</dict>
@@ -2,10 +2,10 @@ import Flutter
import UIKit
import UserNotifications
final class KometNotifications: NSObject {
static let shared = KometNotifications()
final class QlyraNotifications: NSObject {
static let shared = QlyraNotifications()
private static let chatKeys = ["komet_chat", "chatId", "chat_id"]
private static let chatKeys = ["qlyra_chat", "chatId", "chat_id"]
private var sink: FlutterEventSink?
private var pendingChatId: Int64 = 0
@@ -76,7 +76,7 @@ final class KometNotifications: NSObject {
}
}
extension KometNotifications: UNUserNotificationCenterDelegate {
extension QlyraNotifications: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
@@ -54,10 +54,10 @@ private struct VideoExportSpec {
}
}
final class KometVideo {
static let shared = KometVideo()
final class QlyraVideo {
static let shared = QlyraVideo()
private let queue = DispatchQueue(label: "ru.komet.app.video", qos: .userInitiated)
private let queue = DispatchQueue(label: "ru.qlyra.app.video", qos: .userInitiated)
private var session: AVAssetExportSession?
private var cancelled = false
@@ -3,7 +3,7 @@ import CoreImage
import Flutter
import UIKit
final class KometVideoNoteTexture: NSObject, FlutterTexture {
final class QlyraVideoNoteTexture: NSObject, FlutterTexture {
private let lock = NSLock()
private var latest: CVPixelBuffer?
@@ -21,15 +21,15 @@ final class KometVideoNoteTexture: NSObject, FlutterTexture {
}
}
final class KometVideoNote: NSObject {
final class QlyraVideoNote: NSObject {
private let registry: FlutterTextureRegistry
private let queue = DispatchQueue(label: "ru.komet.app.videonote", qos: .userInitiated)
private let queue = DispatchQueue(label: "ru.qlyra.app.videonote", qos: .userInitiated)
private let ciContext = CIContext(options: [.useSoftwareRenderer: false])
private let session = AVCaptureSession()
private let videoOutput = AVCaptureVideoDataOutput()
private let audioOutput = AVCaptureAudioDataOutput()
private let texture = KometVideoNoteTexture()
private let texture = QlyraVideoNoteTexture()
private var textureId: Int64 = 0
private var deviceInput: AVCaptureDeviceInput?
@@ -207,12 +207,12 @@ final class KometVideoNote: NSObject {
guard let device = AVCaptureDevice.default(
.builtInWideAngleCamera, for: .video, position: position)
?? AVCaptureDevice.default(for: .video) else {
throw NSError(domain: "KometVideoNote", code: 1,
throw NSError(domain: "QlyraVideoNote", code: 1,
userInfo: [NSLocalizedDescriptionKey: "no camera found"])
}
let input = try AVCaptureDeviceInput(device: device)
guard session.canAddInput(input) else {
throw NSError(domain: "KometVideoNote", code: 2,
throw NSError(domain: "QlyraVideoNote", code: 2,
userInfo: [NSLocalizedDescriptionKey: "camera input rejected"])
}
session.addInput(input)
@@ -270,7 +270,7 @@ final class KometVideoNote: NSObject {
private func prepareWriter() throws {
let directory = FileManager.default.temporaryDirectory
let url = directory.appendingPathComponent(
"komet_note_\(Int(Date().timeIntervalSince1970 * 1000)).mp4")
"qlyra_note_\(Int(Date().timeIntervalSince1970 * 1000)).mp4")
try? FileManager.default.removeItem(at: url)
let writer = try AVAssetWriter(outputURL: url, fileType: .mp4)
@@ -286,7 +286,7 @@ final class KometVideoNote: NSObject {
let video = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
video.expectsMediaDataInRealTime = true
guard writer.canAdd(video) else {
throw NSError(domain: "KometVideoNote", code: 3,
throw NSError(domain: "QlyraVideoNote", code: 3,
userInfo: [NSLocalizedDescriptionKey: "video input rejected"])
}
writer.add(video)
@@ -310,7 +310,7 @@ final class KometVideoNote: NSObject {
])
guard writer.startWriting() else {
throw NSError(domain: "KometVideoNote", code: 4,
throw NSError(domain: "QlyraVideoNote", code: 4,
userInfo: [NSLocalizedDescriptionKey: "writer refused to start"])
}
@@ -363,7 +363,7 @@ final class KometVideoNote: NSObject {
}
}
extension KometVideoNote: AVCaptureVideoDataOutputSampleBufferDelegate,
extension QlyraVideoNote: AVCaptureVideoDataOutputSampleBufferDelegate,
AVCaptureAudioDataOutputSampleBufferDelegate {
func captureOutput(
_ output: AVCaptureOutput,
+1 -1
View File
@@ -4,7 +4,7 @@
<dict>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)ru.komet.app</string>
<string>$(AppIdentifierPrefix)ru.qlyra.app</string>
</array>
</dict>
</plist>
+12 -12
View File
@@ -4,13 +4,13 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:kolibri/kolibri.dart';
import 'package:kusoft/kusoft.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import '../core/cache/self_presence.dart';
import '../core/config/config.dart';
import '../core/config/countries.dart';
import '../core/config/komet_settings.dart';
import '../core/config/qlyra_settings.dart';
import '../core/config/proxy_config.dart';
import '../core/protocol/opcode_map.dart';
import '../core/protocol/packet.dart';
@@ -27,11 +27,11 @@ enum SessionState { disconnected, connecting, connected, online }
/// Клиент API.
///
/// Тонкий адаптер над Rust-ядром [KolibriSession] (пакет kolibri): подключение,
/// Тонкий адаптер над Rust-ядром [KusoftSession] (пакет kusoft): подключение,
/// хэндшейк, пинг и реконнект живут в ядре, здесь — оркестрация жизненного цикла
/// и сохранение прежнего интерфейса для модулей (Packet/пуши/стримы).
class Api {
KolibriSession? _session;
KusoftSession? _session;
/// Роутер пушей (ответы на запросы ядро матчит само, диспетчер держим только
/// ради registerHandler/pushStream).
@@ -60,7 +60,7 @@ class Api {
String? get callsOsVersion => _callsOsVersion;
/// Сырой доступ к сессии ядра — для медиа-загрузок (data-plane).
KolibriSession? get session => _session;
KusoftSession? get session => _session;
String? spoofScope;
@@ -284,7 +284,7 @@ class Api {
}
// Лог запроса/ответа ведётся из wire-лога ядра (_onWireLog) по настоящему
// проводному seq, поэтому здесь ничего не пишем.
final KolibriResponse resp = await session
final KusoftResponse resp = await session
.requestMapFull(opcode, Map<String, dynamic>.from(payload))
.timeout(
ServerConfig.requestTimeout,
@@ -368,7 +368,7 @@ class Api {
/// Строит устройство-поля и создаёт сессию ядра. Заодно заполняет
/// [_userAgent] и [_deviceId] для геттеров.
Future<(KolibriSession, Stream<WireLogEvent>)> _buildSessionOptions(
Future<(KusoftSession, Stream<WireLogEvent>)> _buildSessionOptions(
({String host, int port, bool trustMincifryCa}) endpoint,
) async {
final deviceInfo = DeviceInfoPlugin();
@@ -513,7 +513,7 @@ class Api {
deviceLocale: deviceLocale,
clientSessionId: clientSessionId,
pingIntervalSecs: ServerConfig.pingInterval.inSeconds,
pingInteractive: !KometSettings.ghostMode.value,
pingInteractive: !QlyraSettings.ghostMode.value,
autoReconnect: false,
insecureTls: insecureTls,
proxy: proxy,
@@ -665,7 +665,7 @@ class Api {
try {
await session
.requestMapFull(Opcode.ping, {
'interactive': !KometSettings.ghostMode.value,
'interactive': !QlyraSettings.ghostMode.value,
})
.timeout(const Duration(seconds: 6));
} catch (_) {
@@ -720,7 +720,7 @@ class Api {
/// синхронизация interactive-флага пинга и присутствия.
void _startLiveness() {
_livenessTimer?.cancel();
_lastInteractive = !KometSettings.ghostMode.value;
_lastInteractive = !QlyraSettings.ghostMode.value;
_livenessTimer = Timer.periodic(_livenessInterval, (_) => _tickLiveness());
}
@@ -729,11 +729,11 @@ class Api {
if (session == null || _sessionState != SessionState.online) return;
final st = session.state();
if (st != 'online' && st != 'connected') {
logger.w('kolibri сессия "$st" — реконнект');
logger.w('kusoft сессия "$st" — реконнект');
_onDisconnected();
return;
}
final interactive = !KometSettings.ghostMode.value;
final interactive = !QlyraSettings.ghostMode.value;
if (interactive != _lastInteractive) {
_lastInteractive = interactive;
try {
+11 -5
View File
@@ -3,7 +3,7 @@ import 'dart:convert';
import 'dart:typed_data';
import '../api.dart';
import '../../core/config/debug_test.dart';
import '../../core/config/komet_settings.dart';
import '../../core/config/qlyra_settings.dart';
import '../../core/protocol/chat_cache_fingerprint.dart';
import '../../core/protocol/opcode_map.dart';
import '../../core/protocol/packet.dart';
@@ -534,7 +534,7 @@ class AccountModule {
}) {
final payload = <dynamic, dynamic>{
'token': token,
'interactive': interactive ?? !KometSettings.ghostMode.value,
'interactive': interactive ?? !QlyraSettings.ghostMode.value,
'exp': {
'chatsCountGroups': Uint8List.fromList([0x0b, 0x32]),
},
@@ -645,7 +645,9 @@ class AccountModule {
Future<ProfileData> _resurrectProfile(int accountId) async {
if (DebugTest.berserk) {
await AppDatabase.deleteAccount(accountId);
logger.w('login: [BERSERK] профиль удалён из БД, форсирую регенерацию (id=$accountId)');
logger.w(
'login: [BERSERK] профиль удалён из БД, форсирую регенерацию (id=$accountId)',
);
} else {
final cached = await AppDatabase.loadProfile(accountId);
if (cached != null) return cached;
@@ -656,11 +658,15 @@ class AccountModule {
try {
final fetched = await ContactsModule.fetchSelfProfile(_api, accountId);
if (fetched != null) {
logger.i('login: профиль восстановлен через CONTACT_INFO (id=$accountId)');
logger.i(
'login: профиль восстановлен через CONTACT_INFO (id=$accountId)',
);
return fetched;
}
} catch (e) {
logger.w('login: восстановление профиля через CONTACT_INFO не удалось: $e');
logger.w(
'login: восстановление профиля через CONTACT_INFO не удалось: $e',
);
}
logger.w('login: профиль недоступен, использую заглушку (id=$accountId)');
+1 -1
View File
@@ -20,7 +20,7 @@ class AnimojiModule {
'😍',
];
static const String _recentsKey = 'komet_recent_animoji';
static const String _recentsKey = 'qlyra_recent_animoji';
static const int _maxRecents = 24;
final Map<int, Animoji> _byId = {};
+8 -7
View File
@@ -266,13 +266,14 @@ int? _otherParticipantId(dynamic participants, int currentUserId) {
String? _nameFromContact(Map<dynamic, dynamic> contact) {
final names = contact['names'];
if (names is! List || names.isEmpty) return null;
final nameRaw = names.firstWhere(
(n) => n is Map && n['type'] == 'ONEME',
orElse: () => names.firstWhere((n) => n is Map, orElse: () => null),
);
if (nameRaw is! Map) return null;
final name = nameRaw;
return name['name'] as String?;
Map<dynamic, dynamic>? fallback;
for (final entry in names) {
if (entry is! Map) continue;
final name = entry.cast<dynamic, dynamic>();
fallback ??= name;
if (name['type'] == 'ONEME') return name['name'] as String?;
}
return fallback?['name'] as String?;
}
List<ChatSearchHit> parseSearchResult(dynamic payload) {
+7 -7
View File
@@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import '../../core/config/komet_settings.dart';
import '../../core/config/qlyra_settings.dart';
import '../../core/protocol/opcode_map.dart';
import '../../core/protocol/packet.dart';
import '../../core/cache/info_cache.dart';
@@ -446,7 +446,7 @@ class ChatsModule {
/// Sentinel в `lastMsgText` когда последнее сообщение в чате удалено,
/// а кеша истории нет — UI должен отрисовать курсивную плашку.
static const String lastMsgPlaceholder = '__komet_lastmsg_placeholder__';
static const String lastMsgPlaceholder = '__qlyra_lastmsg_placeholder__';
ChatsModule._();
@@ -472,7 +472,7 @@ class ChatsModule {
if ((row['unread_count'] as int? ?? 0) == 0) return;
final msgIdNum = int.tryParse(messageId);
if (msgIdNum != null && !KometSettings.antiRead.value) {
if (msgIdNum != null && !QlyraSettings.antiRead.value) {
try {
await api.sendRequest(Opcode.chatMark, {
'type': 'READ_MESSAGE',
@@ -501,7 +501,7 @@ class ChatsModule {
required int remaining,
}) async {
final msgIdNum = int.tryParse(messageId);
if (msgIdNum != null && !KometSettings.antiRead.value) {
if (msgIdNum != null && !QlyraSettings.antiRead.value) {
try {
await api.sendRequest(Opcode.chatMark, {
'type': 'READ_MESSAGE',
@@ -737,7 +737,7 @@ class ChatsModule {
}
if (chatId == null) return;
final keepDeleted = KometSettings.viewDeleted.value;
final keepDeleted = QlyraSettings.viewDeleted.value;
final ids = payload['messageIds'];
if (ids is List) {
for (final raw in ids) {
@@ -803,7 +803,7 @@ class ChatsModule {
}
if (status == 'REMOVED' && msgIdStr != null) {
final keepDeleted = KometSettings.viewDeleted.value;
final keepDeleted = QlyraSettings.viewDeleted.value;
if (keepDeleted) {
await AppDatabase.markMessageDeleted(accountId, chatId, msgIdStr);
} else {
@@ -847,7 +847,7 @@ class ChatsModule {
mergedPayload[entry.key.toString()] = entry.value;
}
final newRow = Map<String, dynamic>.from(existing);
if (KometSettings.viewRedacted.value) {
if (QlyraSettings.viewRedacted.value) {
final oldText = existing['text']?.toString();
if ((oldText ?? '') != (msgText ?? '') &&
oldText != null &&
+3 -6
View File
@@ -11,11 +11,7 @@ class CommentsInfo {
final String postId;
final int? totalCount;
final int? updatedAt;
const CommentsInfo({
required this.postId,
this.totalCount,
this.updatedAt,
});
const CommentsInfo({required this.postId, this.totalCount, this.updatedAt});
factory CommentsInfo.fromPayload(String postId, Map payload) {
final raw = payload['totalCount'];
@@ -98,7 +94,8 @@ class CommentsModule {
final link = msg['link'];
final postId =
(payload['postId'] ?? (link is Map ? link['postId'] : null) ??
(payload['postId'] ??
(link is Map ? link['postId'] : null) ??
msg['postId'])
?.toString();
if (postId == null || postId.isEmpty) return;
+1 -1
View File
@@ -577,7 +577,7 @@ class ContactsModule {
firstName: '$first ${i + 1}',
lastName: last,
phone: 79000000000 + i,
baseUrl: 'https://i.pravatar.cc/150?u=komet_debug_$i',
baseUrl: 'https://i.pravatar.cc/150?u=qlyra_debug_$i',
updateTime: 1,
options: i % 6 == 0 ? const {'OFFICIAL'} : const {},
),
+31 -35
View File
@@ -3,7 +3,7 @@ import 'dart:convert' show jsonDecode, utf8;
import 'dart:io';
import 'dart:typed_data';
import 'package:kolibri/kolibri.dart' as kb;
import 'package:kusoft/kusoft.dart' as kb;
import '../api.dart';
import '../../core/protocol/opcode_map.dart';
@@ -47,7 +47,7 @@ class UploadError extends UploadEvent {
}
/// Оркестратор медиа-загрузок: control-plane (URL, отправка сообщения) идёт
/// обычными опкодами, data-plane (заливка на CDN) — через Rust-ядро kolibri,
/// обычными опкодами, data-plane (заливка на CDN) — через Rust-ядро kusoft,
/// которое стримит файл с диска (не держит его целиком в памяти).
class FileUploader {
final Api api;
@@ -101,39 +101,35 @@ class FileUploader {
var status = 0;
String? error;
final done = Completer<void>();
sub =
session
.uploadFilePath(
url: info.url,
path: file.path,
filename: filename,
connection: 'close',
)
.listen(
(e) {
switch (e) {
case kb.UploadEvent_Progress(:final sent, :final total):
ctrl.add(
UploadProgress(
sent: sent.toInt(),
total: total.toInt(),
),
);
case kb.UploadEvent_Done(status: final s):
status = s;
case kb.UploadEvent_Error(:final message):
error = message;
}
},
onError: (Object err) {
error = err.toString();
if (!done.isCompleted) done.complete();
},
onDone: () {
if (!done.isCompleted) done.complete();
},
cancelOnError: true,
);
sub = session
.uploadFilePath(
url: info.url,
path: file.path,
filename: filename,
connection: 'close',
)
.listen(
(e) {
switch (e) {
case kb.UploadEvent_Progress(:final sent, :final total):
ctrl.add(
UploadProgress(sent: sent.toInt(), total: total.toInt()),
);
case kb.UploadEvent_Done(status: final s):
status = s;
case kb.UploadEvent_Error(:final message):
error = message;
}
},
onError: (Object err) {
error = err.toString();
if (!done.isCompleted) done.complete();
},
onDone: () {
if (!done.isCompleted) done.complete();
},
cancelOnError: true,
);
await done.future;
if (cancelled) return;
if (error != null) {
+2 -2
View File
@@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../api.dart';
import '../../core/config/komet_settings.dart';
import '../../core/config/qlyra_settings.dart';
import '../../core/contacts/device_contacts_service.dart';
import '../../core/protocol/opcode_map.dart';
import '../../core/protocol/packet.dart';
@@ -737,7 +737,7 @@ class MessagesModule {
}
}
final toSave = KometSettings.viewRedacted.value && results.isNotEmpty
final toSave = QlyraSettings.viewRedacted.value && results.isNotEmpty
? await _mergeEditHistory(accountId, chatId, results)
: results;
+2 -2
View File
@@ -2,7 +2,7 @@ import 'dart:async';
import '../../core/cache/info_cache.dart';
import '../../core/cache/self_presence.dart';
import '../../core/config/komet_settings.dart';
import '../../core/config/qlyra_settings.dart';
import '../../core/storage/token_storage.dart';
import '../../core/utils/logger.dart';
import '../api.dart';
@@ -40,7 +40,7 @@ class SelfCheckService {
Future<void> _check() async {
final api = _api;
if (api == null || api.state != SessionState.online) return;
if (!KometSettings.selfOnlineCheck.value) return;
if (!QlyraSettings.selfOnlineCheck.value) return;
final accountId = await TokenStorage.getActiveAccountId();
if (accountId == null) return;
final presence = await PresenceFetch.get(accountId, forceRefresh: true);
+4 -7
View File
@@ -45,9 +45,7 @@ class StoriesModule {
int _nowMs() => DateTime.now().millisecondsSinceEpoch;
int _normMs(int t) => t <= 0
? 0
: (t < 1000000000000 ? t * 1000 : t);
int _normMs(int t) => t <= 0 ? 0 : (t < 1000000000000 ? t * 1000 : t);
// ── Кэш (SQLite) ───────────────────────────────────────────────────────
@@ -196,9 +194,7 @@ class StoriesModule {
final chunk = missing.sublist(i, end);
try {
final packet = await _api.sendRequest(Opcode.storiesGetByOwner, {
'owners': [
for (final id in chunk) StoryOwner(ownerId: id).toMap(),
],
'owners': [for (final id in chunk) StoryOwner(ownerId: id).toMap()],
}, silent: true);
if (packet.isError) continue;
if (_applyOwnerPayload(packet.payload, chunk)) changed = true;
@@ -230,7 +226,8 @@ class StoriesModule {
}
}
for (final id in requested) {
if (!seen.contains(id) && _peerPreviews.remove(id) != null) changed = true;
if (!seen.contains(id) && _peerPreviews.remove(id) != null)
changed = true;
}
final rawPeers = data['peerStories'];
if (rawPeers is List) {
@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import '../../l10n/app_localizations.dart';
import '../../main.dart' show KometApp;
import '../../main.dart' show QlyraApp;
enum UploadKind { photo, video, videoNote, voice, file }
@@ -53,7 +53,7 @@ class _NotificationJob {
class UploadNotificationService {
static const MethodChannel _channel = MethodChannel(
'ru.komet.app/upload_service',
'ru.qlyra.app/upload_service',
);
static const int _minIntervalMs = 350;
static const Duration _startDelay = Duration(milliseconds: 700);
@@ -189,7 +189,7 @@ class UploadNotificationService {
}
static AppLocalizations _localizations() {
final context = KometApp.navigatorKey.currentContext;
final context = QlyraApp.navigatorKey.currentContext;
if (context != null) {
final scoped = Localizations.of<AppLocalizations>(
context,
+3 -1
View File
@@ -91,7 +91,9 @@ class WebAppModule {
throw const WebAppUnavailable('Нет соединения с сервером');
}
final normalizedStartParam =
(startParam != null && startParam.trim().isNotEmpty) ? startParam : null;
(startParam != null && startParam.trim().isNotEmpty)
? startParam
: null;
final packet = await _api.sendRequest(Opcode.webAppInitData, {
'botId': botId,
'startParam': ?normalizedStartParam,
+1 -2
View File
@@ -4,8 +4,7 @@ class SelfPresence {
static final ValueNotifier<bool> isOnline = ValueNotifier(true);
static final ValueNotifier<int?> lastSeenSeconds = ValueNotifier(null);
static int get _nowSeconds =>
DateTime.now().millisecondsSinceEpoch ~/ 1000;
static int get _nowSeconds => DateTime.now().millisecondsSinceEpoch ~/ 1000;
static void markOnline() {
isOnline.value = true;
+2 -2
View File
@@ -11,8 +11,8 @@ class CallBridge {
CallBridge._();
static final CallBridge instance = CallBridge._();
static const _method = MethodChannel('ru.komet.app/calls');
static const _events = EventChannel('ru.komet.app/calls_events');
static const _method = MethodChannel('ru.qlyra.app/calls');
static const _events = EventChannel('ru.qlyra.app/calls_events');
bool _started = false;

Some files were not shown because too many files have changed in this diff Show More