Compare commits
10 Commits
b1ef5803dc
...
5947edec45
| Author | SHA1 | Date | |
|---|---|---|---|
| 5947edec45 | |||
|
|
cd536ff8f2 | ||
|
|
d3e04dbd46 | ||
|
|
1d1dd43c96 | ||
|
|
601defa3ee | ||
|
|
dc2495dca0 | ||
|
|
c75898546a | ||
|
|
d8c2bdf404 | ||
|
|
252d550c07 | ||
|
|
4b8e0752e5 |
12
.metadata
@@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "20f82749394e68bcfbbeee96bad384abaae09c13"
|
revision: "582a0e7c5581dc0ca5f7bfd8662bb8db6f59d536"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
@@ -13,11 +13,11 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 20f82749394e68bcfbbeee96bad384abaae09c13
|
create_revision: 582a0e7c5581dc0ca5f7bfd8662bb8db6f59d536
|
||||||
base_revision: 20f82749394e68bcfbbeee96bad384abaae09c13
|
base_revision: 582a0e7c5581dc0ca5f7bfd8662bb8db6f59d536
|
||||||
- platform: macos
|
- platform: linux
|
||||||
create_revision: 20f82749394e68bcfbbeee96bad384abaae09c13
|
create_revision: 582a0e7c5581dc0ca5f7bfd8662bb8db6f59d536
|
||||||
base_revision: 20f82749394e68bcfbbeee96bad384abaae09c13
|
base_revision: 582a0e7c5581dc0ca5f7bfd8662bb8db6f59d536
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Conduit Privacy Policy
|
# iiEasy Privacy Policy
|
||||||
|
|
||||||
Effective date: 2025-08-09
|
Effective date: 2025-08-09
|
||||||
|
|
||||||
Conduit is an open‑source mobile client for Open‑WebUI. This app acts as a client to a server you choose and configure. This policy describes how the app itself handles data on your device. Your configured server may collect, process, and store data under its own policies; please review your server's privacy terms separately.
|
iiEasy is a mobile client for Open‑WebUI (based on the open-source Conduit project). This app acts as a client to a server you choose and configure. This policy describes how the app itself handles data on your device. Your configured server may collect, process, and store data under its own policies; please review your server's privacy terms separately.
|
||||||
|
|
||||||
## Information We Collect
|
## Information We Collect
|
||||||
- Device-stored data: minimal settings and preferences (e.g., theme, UI options) saved locally on your device.
|
- Device-stored data: minimal settings and preferences (e.g., theme, UI options) saved locally on your device.
|
||||||
@@ -20,7 +20,7 @@ Conduit is an open‑source mobile client for Open‑WebUI. This app acts as a c
|
|||||||
- Network transfer: when you interact with the app, your data is sent to the server you configured. The app does not send your data to any developer‑controlled servers.
|
- Network transfer: when you interact with the app, your data is sent to the server you configured. The app does not send your data to any developer‑controlled servers.
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
Depending on how you use Conduit, the app may request:
|
Depending on how you use iiEasy, the app may request:
|
||||||
- Microphone: to capture voice input when you opt in.
|
- Microphone: to capture voice input when you opt in.
|
||||||
- Photos/Files: to let you pick and upload attachments.
|
- Photos/Files: to let you pick and upload attachments.
|
||||||
- Network access: to connect to your configured server.
|
- Network access: to connect to your configured server.
|
||||||
@@ -40,12 +40,12 @@ We use platform‑provided secure storage for sensitive credentials where suppor
|
|||||||
- You can choose not to grant optional permissions; some features may not work without them.
|
- You can choose not to grant optional permissions; some features may not work without them.
|
||||||
|
|
||||||
## Children’s Privacy
|
## Children’s Privacy
|
||||||
Conduit is not directed to children under 13 (or the minimum age required in your jurisdiction). Do not use the app if you do not meet the applicable age requirements.
|
iiEasy is not directed to children under 13 (or the minimum age required in your jurisdiction). Do not use the app if you do not meet the applicable age requirements.
|
||||||
|
|
||||||
## Changes to This Policy
|
## Changes to This Policy
|
||||||
We may update this policy to reflect improvements or legal requirements. Material changes will be reflected in the app bundle and version notes.
|
We may update this policy to reflect improvements or legal requirements. Material changes will be reflected in the app bundle and version notes.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
For questions or requests about this policy, please contact the app maintainer(s) through the project repository.
|
For questions or requests about this policy, please contact us at [iiEasy.ru](https://iiEasy.ru).
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
74
README.md
@@ -1,16 +1,11 @@
|
|||||||
# Conduit
|
# iiEasy
|
||||||
|
|
||||||
|
**iiEasy** — мобильный клиент для Open-WebUI на базе [Conduit](https://github.com/cogwheel0/conduit). Нативная работа с вашей self-hosted AI инфраструктурой.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|
<a href="https://iiEasy.ru">
|
||||||

|
<img src="docs/store-badges/google.webp" alt="iiEasy" style="height:56px;"/>
|
||||||
|
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=app.cogwheel.conduit">
|
|
||||||
<img src="docs/store-badges/google.webp" alt="Get it on Google Play" style="height:56px;"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287">
|
|
||||||
<img src="docs/store-badges/apple.webp" alt="Download on the App Store" style="height:56px;"/>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -18,12 +13,12 @@
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="docs/screenshots/conduit-demo.gif" alt="Conduit Demo" style="height:600px;"/>
|
<img src="docs/screenshots/conduit-demo.gif" alt="iiEasy Demo" style="height:600px;"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
Conduit is an open-source, cross-platform mobile application for Open-WebUI, providing a native mobile experience for interacting with your self-hosted AI infrastructure.
|
iiEasy is a cross-platform mobile application for Open-WebUI (based on the open-source Conduit project), providing a native mobile experience for interacting with your self-hosted AI infrastructure.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
@@ -71,13 +66,13 @@ flutter run -d ios # or: -d android
|
|||||||
- **Tools (Function Calling)**: Invoke server-side tools exposed by Open‑WebUI, with result rendering
|
- **Tools (Function Calling)**: Invoke server-side tools exposed by Open‑WebUI, with result rendering
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
Conduit supports multiple authentication flows when connecting to your Open‑WebUI:
|
iiEasy supports multiple authentication flows when connecting to your Open‑WebUI (same as Conduit):
|
||||||
- **Username + Password**: Sign in directly against servers that expose a login endpoint. Credentials are stored securely using platform keychains.
|
- **Username + Password**: Sign in directly against servers that expose a login endpoint. Credentials are stored securely using platform keychains.
|
||||||
- **SSO / OAuth** (iOS & Android): Authenticate via your server's configured OAuth providers (Google, Microsoft, GitHub, OIDC, etc.) using an in-app WebView. The token is automatically captured after the OAuth flow completes.
|
- **SSO / OAuth** (iOS & Android): Authenticate via your server's configured OAuth providers (Google, Microsoft, GitHub, OIDC, etc.) using an in-app WebView. The token is automatically captured after the OAuth flow completes.
|
||||||
- **Reverse Proxy Support** (iOS & Android): Seamlessly connect to Open WebUI instances behind authentication proxies like oauth2-proxy, Authelia, Authentik, Pangolin, Cloudflare Tunnel, etc. Conduit automatically detects when proxy authentication is required and guides you through the login flow—no endpoint allowlisting or server-side configuration needed. Proxy session cookies are captured from the native cookie store and included in all subsequent API requests.
|
- **Reverse Proxy Support** (iOS & Android): Seamlessly connect to Open WebUI instances behind authentication proxies like oauth2-proxy, Authelia, Authentik, Pangolin, Cloudflare Tunnel, etc. Conduit automatically detects when proxy authentication is required and guides you through the login flow—no endpoint allowlisting or server-side configuration needed. Proxy session cookies are captured from the native cookie store and included in all subsequent API requests.
|
||||||
- **LDAP**: Sign in using LDAP credentials if enabled on your server.
|
- **LDAP**: Sign in using LDAP credentials if enabled on your server.
|
||||||
- **JWT Token**: Paste a server‑issued JWT token for manual token-based auth.
|
- **JWT Token**: Paste a server‑issued JWT token for manual token-based auth.
|
||||||
- **Custom Headers**: Add headers during login (e.g., `X-API-Key`, `Authorization`, `X-Org`) that Conduit will include on all HTTP/WebSocket requests.
|
- **Custom Headers**: Add headers during login (e.g., `X-API-Key`, `Authorization`, `X-Org`) that iiEasy will include on all HTTP/WebSocket requests.
|
||||||
|
|
||||||
The authentication page dynamically displays available options based on your server's configuration.
|
The authentication page dynamically displays available options based on your server's configuration.
|
||||||
|
|
||||||
@@ -124,17 +119,49 @@ flutter run -d android
|
|||||||
## Building for Release
|
## Building for Release
|
||||||
|
|
||||||
### Android
|
### Android
|
||||||
|
|
||||||
|
**Если Flutter пишет «No Android SDK found» или «Android SDK not found at this location»:** переменная `ANDROID_HOME` должна указывать на каталог, где **реально установлен** SDK. Пустая или несуществующая папка не подойдёт.
|
||||||
|
|
||||||
|
1. **Вариант А — Android Studio**
|
||||||
|
Установите с [developer.android.com/studio](https://developer.android.com/studio). При первом запуске выберите установку SDK — он появится в `~/Android/Sdk`.
|
||||||
|
|
||||||
|
2. **Вариант Б — только command-line tools (без Android Studio)**
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/Android/Sdk/cmdline-tools
|
||||||
|
cd ~/Android/Sdk
|
||||||
|
# Скачать с https://developer.android.com/studio#command-tools (Linux)
|
||||||
|
# Распаковать так, чтобы внутри было cmdline-tools/latest/bin/sdkmanager
|
||||||
|
unzip -q commandlinetools-linux-*.zip && mv cmdline-tools latest && mv latest cmdline-tools/
|
||||||
|
export ANDROID_HOME="$HOME/Android/Sdk"
|
||||||
|
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"
|
||||||
|
yes | sdkmanager --licenses
|
||||||
|
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
|
||||||
|
```
|
||||||
|
3. **Настройте окружение** (добавьте в `~/.bashrc` и выполните `source ~/.bashrc` или откройте новый терминал):
|
||||||
|
```bash
|
||||||
|
export ANDROID_HOME="$HOME/Android/Sdk"
|
||||||
|
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"
|
||||||
|
```
|
||||||
|
4. Примите лицензии: `flutter doctor --android-licenses` (все запросы — `y`).
|
||||||
|
5. Проверка: `flutter doctor -v` — в блоке Android toolchain не должно быть ошибок.
|
||||||
|
|
||||||
|
После этого:
|
||||||
```bash
|
```bash
|
||||||
flutter build apk --release
|
flutter build apk --release
|
||||||
# or for App Bundle
|
# или для выгрузки в Google Play
|
||||||
flutter build appbundle --release
|
flutter build appbundle --release
|
||||||
```
|
```
|
||||||
|
APK: `build/app/outputs/flutter-apk/app-release.apk`
|
||||||
|
AAB: `build/app/outputs/bundle/release/app-release.aab`
|
||||||
|
|
||||||
### iOS
|
### iOS
|
||||||
```bash
|
```bash
|
||||||
flutter build ios --release
|
flutter build ios --release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Linux (desktop)
|
||||||
|
Если сборка под Linux падает с ошибкой линковки (`libsecret`, `undefined reference to g_task_set_static_name` и т.п.), это типично для **Flutter из snap**: в snap старая glibc, а системные библиотеки (libsecret, glib) требуют новую. Решение: ставить Flutter **не из snap** — [официальная установка](https://docs.flutter.dev/get-started/install/linux) (manual install). После установки Flutter вручную `flutter run -d linux` и `flutter build linux` должны собираться. Для проверки приложения без Linux-сборки можно использовать эмулятор Android или устройство.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Android
|
### Android
|
||||||
@@ -180,17 +207,7 @@ lib/
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Conduit is currently in active development. We welcome your feedback and contributions!
|
iiEasy is based on Conduit. For upstream contributions and discussions, see the [Conduit repository](https://github.com/cogwheel0/conduit). For iiEasy-specific feedback and support, visit [iiEasy.ru](https://iiEasy.ru).
|
||||||
|
|
||||||
**How to Contribute:**
|
|
||||||
|
|
||||||
- **Bug Reports**: Found a bug? Please [create an issue](https://github.com/cogwheel0/conduit/issues) with details about the problem, steps to reproduce, and your device/platform information.
|
|
||||||
|
|
||||||
- **Feature Requests**: Have an idea for a new feature? Start a [discussion](https://github.com/cogwheel0/conduit/discussions) to share your ideas and gather feedback from the community.
|
|
||||||
|
|
||||||
- **Questions & Feedback**: Use [GitHub Discussions](https://github.com/cogwheel0/conduit/discussions) to ask questions, share your experience, or discuss the project.
|
|
||||||
|
|
||||||
**Note:** As the project is actively evolving, we're not accepting pull requests at this time. Instead, please use issues and discussions to share your ideas, report bugs, and contribute to the project's development.
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -217,8 +234,9 @@ This project is licensed under the GPL3 License - see the LICENSE file for detai
|
|||||||
- <a href="https://vercel.com/oss"><img alt="Vercel OSS Program" src="https://vercel.com/oss/program-badge.svg" /></a>
|
- <a href="https://vercel.com/oss"><img alt="Vercel OSS Program" src="https://vercel.com/oss/program-badge.svg" /></a>
|
||||||
- Open-WebUI team for creating an amazing self-hosted AI interface
|
- Open-WebUI team for creating an amazing self-hosted AI interface
|
||||||
- Flutter team for the excellent mobile framework
|
- Flutter team for the excellent mobile framework
|
||||||
- All contributors and users of Conduit
|
- Conduit project and all its contributors
|
||||||
|
- All users of iiEasy
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
For issues and feature requests, please use the [GitHub Issues](https://github.com/cogwheel0/conduit/issues) page.
|
For support and information, please visit [iiEasy.ru](https://iiEasy.ru).
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ if (keystorePropertiesFile.exists()) {
|
|||||||
android {
|
android {
|
||||||
namespace = "app.cogwheel.conduit"
|
namespace = "app.cogwheel.conduit"
|
||||||
compileSdk = 36
|
compileSdk = 36
|
||||||
ndkVersion = "29.0.14206865"
|
ndkVersion = "28.0.13004108"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "app.cogwheel.conduit"
|
applicationId = "app.cogwheel.conduit"
|
||||||
@@ -56,8 +56,8 @@ android {
|
|||||||
if (keystorePropertiesFile.exists()) {
|
if (keystorePropertiesFile.exists()) {
|
||||||
signingConfig = signingConfigs.getByName("release")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = false
|
||||||
isShrinkResources = true
|
isShrinkResources = false
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro"
|
"proguard-rules.pro"
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
ForegroundServiceDidNotStartInTimeException. This ensures channels exist before
|
ForegroundServiceDidNotStartInTimeException. This ensures channels exist before
|
||||||
any foreground service attempts to use them. -->
|
any foreground service attempts to use them. -->
|
||||||
<application
|
<application
|
||||||
android:label="Conduit"
|
android:label="iiEasy"
|
||||||
android:name=".ConduitApplication"
|
android:name=".ConduitApplication"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ProcessTextActivity"
|
android:name=".ProcessTextActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="Ask Conduit"
|
android:label="Ask iiEasy"
|
||||||
android:noHistory="true">
|
android:noHistory="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class BackgroundStreamingService : Service() {
|
|||||||
// Otherwise startForeground throws "Bad notification" error
|
// Otherwise startForeground throws "Bad notification" error
|
||||||
ensureNotificationChannel()
|
ensureNotificationChannel()
|
||||||
val fallbackNotification = NotificationCompat.Builder(this, CHANNEL_ID)
|
val fallbackNotification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
.setContentTitle("Conduit")
|
.setContentTitle("iiEasy")
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.setSilent(true)
|
.setSilent(true)
|
||||||
.setOngoing(true) // Prevent user from dismissing foreground service notification
|
.setOngoing(true) // Prevent user from dismissing foreground service notification
|
||||||
@@ -264,7 +264,7 @@ class BackgroundStreamingService : Service() {
|
|||||||
|
|
||||||
// Create a minimal, silent notification (required for foreground service)
|
// Create a minimal, silent notification (required for foreground service)
|
||||||
return NotificationCompat.Builder(this, CHANNEL_ID)
|
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
.setContentTitle("Conduit")
|
.setContentTitle("iiEasy")
|
||||||
.setContentText("Background service active")
|
.setContentText("Background service active")
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
@@ -289,7 +289,7 @@ class BackgroundStreamingService : Service() {
|
|||||||
"Background Service",
|
"Background Service",
|
||||||
NotificationManager.IMPORTANCE_MIN,
|
NotificationManager.IMPORTANCE_MIN,
|
||||||
).apply {
|
).apply {
|
||||||
description = "Background service for Conduit"
|
description = "Background service for iiEasy"
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
enableLights(false)
|
enableLights(false)
|
||||||
enableVibration(false)
|
enableVibration(false)
|
||||||
@@ -324,7 +324,7 @@ class BackgroundStreamingService : Service() {
|
|||||||
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
wakeLock = powerManager.newWakeLock(
|
wakeLock = powerManager.newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK,
|
PowerManager.PARTIAL_WAKE_LOCK,
|
||||||
"Conduit::StreamingWakeLock"
|
"iiEasy::StreamingWakeLock"
|
||||||
).apply {
|
).apply {
|
||||||
// Disable reference counting for deterministic single-holder behavior
|
// Disable reference counting for deterministic single-holder behavior
|
||||||
// This prevents accumulation if acquireWakeLock is called multiple times
|
// This prevents accumulation if acquireWakeLock is called multiple times
|
||||||
@@ -728,7 +728,7 @@ class BackgroundStreamingHandler(private val activity: MainActivity) : MethodCal
|
|||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val name = "Background Service"
|
val name = "Background Service"
|
||||||
val descriptionText = "Background service for Conduit"
|
val descriptionText = "Background service for iiEasy"
|
||||||
val importance = NotificationManager.IMPORTANCE_MIN
|
val importance = NotificationManager.IMPORTANCE_MIN
|
||||||
val channel = NotificationChannel(BackgroundStreamingService.CHANNEL_ID, name, importance).apply {
|
val channel = NotificationChannel(BackgroundStreamingService.CHANNEL_ID, name, importance).apply {
|
||||||
description = descriptionText
|
description = descriptionText
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class ConduitApplication : Application() {
|
|||||||
notificationManager,
|
notificationManager,
|
||||||
channelId = BackgroundStreamingService.CHANNEL_ID,
|
channelId = BackgroundStreamingService.CHANNEL_ID,
|
||||||
channelName = "Background Service",
|
channelName = "Background Service",
|
||||||
description = "Background service for Conduit",
|
description = "Background service for iiEasy",
|
||||||
importance = NotificationManager.IMPORTANCE_MIN,
|
importance = NotificationManager.IMPORTANCE_MIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
24
android/app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- iiEasy logo: 3 concentric dashed circles (from assets/icons/logo.svg) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="200"
|
||||||
|
android:viewportHeight="200">
|
||||||
|
<!-- Three concentric circles (solid stroke; dash not supported by AAPT in drawable) -->
|
||||||
|
<path
|
||||||
|
android:pathData="M 170,100 A 70,70 0 1,1 169.99,100"
|
||||||
|
android:strokeColor="#1F2937"
|
||||||
|
android:strokeWidth="6"
|
||||||
|
android:fillColor="#00000000"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M 150,100 A 50,50 0 1,1 149.99,100"
|
||||||
|
android:strokeColor="#1F2937"
|
||||||
|
android:strokeWidth="6"
|
||||||
|
android:fillColor="#00000000"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M 130,100 A 30,30 0 1,1 129.99,100"
|
||||||
|
android:strokeColor="#1F2937"
|
||||||
|
android:strokeWidth="6"
|
||||||
|
android:fillColor="#00000000"/>
|
||||||
|
</vector>
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
android:paddingStart="20dp"
|
android:paddingStart="20dp"
|
||||||
android:paddingEnd="8dp">
|
android:paddingEnd="8dp">
|
||||||
|
|
||||||
<!-- Ask Conduit text -->
|
<!-- Ask iiEasy text -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/input_area"
|
android:id="@+id/input_area"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_toStartOf="@id/btn_voice"
|
android:layout_toStartOf="@id/btn_voice"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:text="Ask Conduit"
|
android:text="Ask iiEasy"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:alpha="0.6"
|
android:alpha="0.6"
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<foreground>
|
||||||
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
<inset
|
||||||
|
android:drawable="@drawable/ic_launcher_foreground"
|
||||||
|
android:inset="16%" />
|
||||||
|
</foreground>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 893 B |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -27,8 +27,5 @@
|
|||||||
<color name="widget_secondary_container_fallback">#E8DEF8</color>
|
<color name="widget_secondary_container_fallback">#E8DEF8</color>
|
||||||
<color name="widget_on_secondary_container_fallback">#1D192B</color>
|
<color name="widget_on_secondary_container_fallback">#1D192B</color>
|
||||||
<color name="widget_surface_fallback">#FFFBFE</color>
|
<color name="widget_surface_fallback">#FFFBFE</color>
|
||||||
|
<color name="ic_launcher_background">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Conduit</string>
|
<string name="app_name">iiEasy</string>
|
||||||
|
|
||||||
<!-- Widget strings -->
|
<!-- Widget strings -->
|
||||||
<string name="widget_name">Conduit</string>
|
<string name="widget_name">iiEasy</string>
|
||||||
<string name="widget_description">Quick access to Conduit chat with camera, photos, and clipboard shortcuts</string>
|
<string name="widget_description">Quick access to iiEasy chat with camera, photos, and clipboard shortcuts</string>
|
||||||
<string name="widget_ask_conduit">Ask Conduit</string>
|
<string name="widget_ask_conduit">Ask iiEasy</string>
|
||||||
<string name="widget_camera">Camera</string>
|
<string name="widget_camera">Camera</string>
|
||||||
<string name="widget_photos">Photos</string>
|
<string name="widget_photos">Photos</string>
|
||||||
<string name="widget_clipboard">Clipboard</string>
|
<string name="widget_clipboard">Clipboard</string>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Conduit is an open-source, native mobile client for Open‑WebUI. Connect to your own server to chat with AI models, manage conversations, and take your self‑hosted AI with you—securely and on the go.
|
iiEasy is a native mobile client for Open‑WebUI, based on the open-source Conduit project. Connect to your own server to chat with AI models, manage conversations, and take your self‑hosted AI with you—securely and on the go.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
- Real-time streaming chat
|
- Real-time streaming chat
|
||||||
@@ -13,7 +13,7 @@ Features
|
|||||||
- Offline-aware experience
|
- Offline-aware experience
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
- Requires an existing Open‑WebUI server. Conduit does not host or provide AI models.
|
- Requires an existing Open‑WebUI server. iiEasy does not host or provide AI models.
|
||||||
- No data is sent to third-party services by default; everything stays with your configured server.
|
- No data is sent to third-party services by default; everything stays with your configured server.
|
||||||
|
|
||||||
Permissions
|
Permissions
|
||||||
@@ -21,11 +21,10 @@ Permissions
|
|||||||
- Camera and Photos/Storage: Image/file attachments
|
- Camera and Photos/Storage: Image/file attachments
|
||||||
- Network: Connect to your Open‑WebUI server
|
- Network: Connect to your Open‑WebUI server
|
||||||
|
|
||||||
Open Source:
|
For support, issues, and more information, please visit:
|
||||||
Conduit is an open-source project. For support, to report issues, or to view the source code, please visit our GitHub repository:
|
|
||||||
|
|
||||||
https://github.com/cogwheel0/conduit
|
https://iiEasy.ru
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Disclaimer: This is an independent, third-party application licensed under the GNU General Public License v3.0 (GPLv3) and is not officially affiliated with the OpenWebUI project.
|
Disclaimer: iiEasyWeb is an independent, third-party application licensed under the GNU General Public License v3.0 (GPLv3) and is not officially affiliated with the OpenWebUI project.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI Client
|
iiEasyWeb
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 76 KiB |
BIN
assets/icons/icon_dark.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
5
assets/icons/logo.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="iiEasy Logo">
|
||||||
|
<circle cx="100" cy="100" r="70" stroke="#1F2937" stroke-width="6" fill="none" stroke-dasharray="15 85" transform="rotate(-90 100 100)"/>
|
||||||
|
<circle cx="100" cy="100" r="50" stroke="#1F2937" stroke-width="6" fill="none" stroke-dasharray="12 58" transform="rotate(-60 100 100)"/>
|
||||||
|
<circle cx="100" cy="100" r="30" stroke="#1F2937" stroke-width="6" fill="none" stroke-dasharray="8 32" transform="rotate(-30 100 100)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 549 B |
5
assets/icons/logo_dark.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="iiEasy Logo (dark)">
|
||||||
|
<circle cx="100" cy="100" r="70" stroke="#FFFFFF" stroke-width="6" fill="none" stroke-dasharray="15 85" transform="rotate(-90 100 100)"/>
|
||||||
|
<circle cx="100" cy="100" r="50" stroke="#FFFFFF" stroke-width="6" fill="none" stroke-dasharray="12 58" transform="rotate(30 100 100)"/>
|
||||||
|
<circle cx="100" cy="100" r="30" stroke="#FFFFFF" stroke-width="6" fill="none" stroke-dasharray="8 32" transform="rotate(60 100 100)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 554 B |
@@ -4,29 +4,29 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Conduit — Your AI, Everywhere</title>
|
<title>iiEasy — Your AI, Everywhere</title>
|
||||||
<meta name="description"
|
<meta name="description"
|
||||||
content="Conduit is an open-source, cross-platform mobile application for Open-WebUI. A native mobile experience for your self-hosted AI infrastructure.">
|
content="iiEasy is a mobile client for Open-WebUI (based on Conduit). A native mobile experience for your self-hosted AI infrastructure.">
|
||||||
|
|
||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://conduit.cogwheel.app/">
|
<meta property="og:url" content="https://iiEasy.ru/">
|
||||||
<meta property="og:title" content="Conduit — Your AI, Everywhere">
|
<meta property="og:title" content="iiEasy — Your AI, Everywhere">
|
||||||
<meta property="og:description" content="The native mobile client for Open-WebUI. Beautiful, fast, and secure.">
|
<meta property="og:description" content="The native mobile client for Open-WebUI. Beautiful, fast, and secure.">
|
||||||
<meta property="og:image" content="https://conduit.cogwheel.app/og-image.png">
|
<meta property="og:image" content="https://iiEasy.ru/og-image.png">
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:url" content="https://conduit.cogwheel.app/">
|
<meta property="twitter:url" content="https://iiEasy.ru/">
|
||||||
<meta property="twitter:title" content="Conduit — Your AI, Everywhere">
|
<meta property="twitter:title" content="iiEasy — Your AI, Everywhere">
|
||||||
<meta property="twitter:description" content="The native mobile client for Open-WebUI. Beautiful, fast, and secure.">
|
<meta property="twitter:description" content="The native mobile client for Open-WebUI. Beautiful, fast, and secure.">
|
||||||
<meta property="twitter:image" content="https://conduit.cogwheel.app/og-image.png">
|
<meta property="twitter:image" content="https://iiEasy.ru/og-image.png">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Crimson+Pro:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Crimson+Pro:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
||||||
<link rel="icon" type="image/png"
|
<link rel="icon" type="image/png"
|
||||||
href="https://raw.githubusercontent.com/cogwheel0/conduit/main/assets/icons/icon.png">
|
href="assets/icons/icon.png">
|
||||||
<script src="https://app.rybbit.io/api/script.js" data-site-id="1c79ee193aa9" defer></script>
|
<script src="https://app.rybbit.io/api/script.js" data-site-id="1c79ee193aa9" defer></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -41,15 +41,15 @@
|
|||||||
|
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="#" class="logo">
|
<a href="https://iiEasy.ru" class="logo">
|
||||||
<img src="https://raw.githubusercontent.com/cogwheel0/conduit/main/assets/icons/icon.png" alt="Conduit" class="logo-icon">
|
<img src="assets/icons/icon.png" alt="iiEasy" class="logo-icon">
|
||||||
<span class="logo-text">Conduit</span>
|
<span class="logo-text">iiEasy</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="nav-links">
|
<div class="nav-links">
|
||||||
<a href="#features">Features</a>
|
<a href="#features">Features</a>
|
||||||
<a href="#gallery">Gallery</a>
|
<a href="#gallery">Gallery</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit" target="_blank" class="nav-cta">
|
<a href="https://iiEasy.ru" target="_blank" class="nav-cta">
|
||||||
<span>View on GitHub</span>
|
<span>iiEasy.ru</span>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<div class="mobile-menu">
|
<div class="mobile-menu">
|
||||||
<a href="#features">Features</a>
|
<a href="#features">Features</a>
|
||||||
<a href="#gallery">Gallery</a>
|
<a href="#gallery">Gallery</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit" target="_blank">GitHub</a>
|
<a href="https://iiEasy.ru" target="_blank">iiEasy.ru</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<header class="hero">
|
<header class="hero">
|
||||||
@@ -76,14 +76,14 @@
|
|||||||
<span class="badge-dot"></span>
|
<span class="badge-dot"></span>
|
||||||
Open Source & Privacy-First
|
Open Source & Privacy-First
|
||||||
</div>
|
</div>
|
||||||
<a href="https://github.com/cogwheel0/conduit" target="_blank" class="social-badge">
|
<a href="https://iiEasy.ru" target="_blank" class="social-badge">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="badge-value" id="github-stars">—</span>
|
<span class="badge-value" id="github-stars">—</span>
|
||||||
<span class="badge-label">Stars</span>
|
<span class="badge-label">Stars</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit/releases" target="_blank" class="social-badge">
|
<a href="https://iiEasy.ru/releases" target="_blank" class="social-badge">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||||
<polyline points="7 10 12 15 17 10"/>
|
<polyline points="7 10 12 15 17 10"/>
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
<div class="hero-device">
|
<div class="hero-device">
|
||||||
<div class="device-glow"></div>
|
<div class="device-glow"></div>
|
||||||
<div class="device-frame">
|
<div class="device-frame">
|
||||||
<img src="screenshots/conduit-demo.gif" alt="Conduit App Demo" loading="eager">
|
<img src="screenshots/conduit-demo.gif" alt="iiEasy App Demo" loading="eager">
|
||||||
</div>
|
</div>
|
||||||
<div class="device-reflection"></div>
|
<div class="device-reflection"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mini-feature">
|
<div class="mini-feature">
|
||||||
<span class="mini-feature-name">Share Extension</span>
|
<span class="mini-feature-name">Share Extension</span>
|
||||||
<span class="mini-feature-desc">Send from any app to Conduit</span>
|
<span class="mini-feature-desc">Send from any app to iiEasy</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -423,7 +423,7 @@
|
|||||||
<div class="category-features">
|
<div class="category-features">
|
||||||
<div class="mini-feature">
|
<div class="mini-feature">
|
||||||
<span class="mini-feature-name">Siri Shortcuts</span>
|
<span class="mini-feature-name">Siri Shortcuts</span>
|
||||||
<span class="mini-feature-desc">"Hey Siri, ask Conduit..."</span>
|
<span class="mini-feature-desc">"Hey Siri, ask iiEasy..."</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mini-feature">
|
<div class="mini-feature">
|
||||||
<span class="mini-feature-name">Android Assistant</span>
|
<span class="mini-feature-name">Android Assistant</span>
|
||||||
@@ -526,7 +526,7 @@
|
|||||||
<div class="cta-card">
|
<div class="cta-card">
|
||||||
<div class="cta-content">
|
<div class="cta-content">
|
||||||
<h2>Ready to get started?</h2>
|
<h2>Ready to get started?</h2>
|
||||||
<p>Join thousands of users who've made Conduit their gateway to self-hosted AI. Open source and available now.</p>
|
<p>Join thousands of users who've made iiEasy their gateway to self-hosted AI. Based on Conduit. Open source and available now.</p>
|
||||||
<div class="cta-buttons">
|
<div class="cta-buttons">
|
||||||
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287" class="btn btn-white">
|
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287" class="btn btn-white">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
||||||
@@ -556,8 +556,8 @@
|
|||||||
<div class="footer-main">
|
<div class="footer-main">
|
||||||
<div class="footer-brand">
|
<div class="footer-brand">
|
||||||
<a href="#" class="logo">
|
<a href="#" class="logo">
|
||||||
<img src="https://raw.githubusercontent.com/cogwheel0/conduit/main/assets/icons/icon.png" alt="Conduit" class="logo-icon">
|
<img src="assets/icons/icon.png" alt="iiEasy" class="logo-icon">
|
||||||
<span class="logo-text">Conduit</span>
|
<span class="logo-text">iiEasy</span>
|
||||||
</a>
|
</a>
|
||||||
<p>The native mobile client for Open-WebUI.<br>Open source. Privacy-first. Beautiful.</p>
|
<p>The native mobile client for Open-WebUI.<br>Open source. Privacy-first. Beautiful.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -566,25 +566,25 @@
|
|||||||
<h4>Product</h4>
|
<h4>Product</h4>
|
||||||
<a href="#features">Features</a>
|
<a href="#features">Features</a>
|
||||||
<a href="#gallery">Gallery</a>
|
<a href="#gallery">Gallery</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit/releases">Releases</a>
|
<a href="https://iiEasy.ru/releases">Releases</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-col">
|
<div class="footer-col">
|
||||||
<h4>Community</h4>
|
<h4>Community</h4>
|
||||||
<a href="https://github.com/cogwheel0/conduit">GitHub</a>
|
<a href="https://iiEasy.ru">GitHub</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit/issues">Issues</a>
|
<a href="https://iiEasy.ru/issues">Issues</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit/discussions">Discussions</a>
|
<a href="https://iiEasy.ru/discussions">Discussions</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-col">
|
<div class="footer-col">
|
||||||
<h4>Legal</h4>
|
<h4>Legal</h4>
|
||||||
<a href="https://github.com/cogwheel0/conduit/blob/main/LICENSE">License (GPLv3)</a>
|
<a href="https://iiEasy.ru/blob/main/LICENSE">License (GPLv3)</a>
|
||||||
<a href="https://github.com/cogwheel0/conduit/blob/main/PRIVACY_POLICY.md">Privacy Policy</a>
|
<a href="https://iiEasy.ru/blob/main/PRIVACY_POLICY.md">Privacy Policy</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-bottom">
|
<div class="footer-bottom">
|
||||||
<p>© 2025 Conduit. Not affiliated with Open-WebUI.</p>
|
<p>© 2025 iiEasy. Based on Conduit. Not affiliated with Open-WebUI.</p>
|
||||||
<div class="footer-social">
|
<div class="footer-social">
|
||||||
<a href="https://github.com/cogwheel0/conduit" aria-label="GitHub">
|
<a href="https://iiEasy.ru" aria-label="GitHub">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -739,7 +739,7 @@
|
|||||||
DEVELOPMENT_TEAM = X2662V5DT2;
|
DEVELOPMENT_TEAM = X2662V5DT2;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Conduit;
|
INFOPLIST_KEY_CFBundleDisplayName = iiEasy;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -813,7 +813,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@@ -870,7 +870,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@@ -925,7 +925,7 @@
|
|||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Debug";
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
@@ -934,7 +934,7 @@
|
|||||||
DEVELOPMENT_TEAM = X2662V5DT2;
|
DEVELOPMENT_TEAM = X2662V5DT2;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Conduit Debug";
|
INFOPLIST_KEY_CFBundleDisplayName = "iiEasy Debug";
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -969,7 +969,7 @@
|
|||||||
DEVELOPMENT_TEAM = X2662V5DT2;
|
DEVELOPMENT_TEAM = X2662V5DT2;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Conduit;
|
INFOPLIST_KEY_CFBundleDisplayName = iiEasy;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -992,8 +992,8 @@
|
|||||||
F15AFED22EE5499E00A1FABB /* Debug */ = {
|
F15AFED22EE5499E00A1FABB /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
@@ -1009,7 +1009,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ConduitWidget;
|
INFOPLIST_KEY_CFBundleDisplayName = iiEasy;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -1038,8 +1038,8 @@
|
|||||||
F15AFED32EE5499E00A1FABB /* Release */ = {
|
F15AFED32EE5499E00A1FABB /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
@@ -1055,7 +1055,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ConduitWidget;
|
INFOPLIST_KEY_CFBundleDisplayName = iiEasy;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -1081,8 +1081,8 @@
|
|||||||
F15AFED42EE5499E00A1FABB /* Profile */ = {
|
F15AFED42EE5499E00A1FABB /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
@@ -1098,7 +1098,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
INFOPLIST_FILE = ConduitWidget/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ConduitWidget;
|
INFOPLIST_KEY_CFBundleDisplayName = iiEasy;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -1141,7 +1141,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = "Ask iiEasy";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -1189,7 +1189,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = "Ask iiEasy";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -1234,7 +1234,7 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = "Ask iiEasy";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
|||||||
@@ -1,134 +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"}}
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"filename": "AppIcon@2x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon@3x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "3x",
|
|
||||||
"size": "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "76x76"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon@2x~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "76x76"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-83.5@2x~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "83.5x83.5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-40@2x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-40@3x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "3x",
|
|
||||||
"size": "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-40~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-40@2x~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-20@2x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-20@3x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "3x",
|
|
||||||
"size": "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-20~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-20@2x~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-29.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-29@2x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-29@3x.png",
|
|
||||||
"idiom": "iphone",
|
|
||||||
"scale": "3x",
|
|
||||||
"size": "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-29~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-29@2x~ipad.png",
|
|
||||||
"idiom": "ipad",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-60@2x~car.png",
|
|
||||||
"idiom": "car",
|
|
||||||
"scale": "2x",
|
|
||||||
"size": "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon-60@3x~car.png",
|
|
||||||
"idiom": "car",
|
|
||||||
"scale": "3x",
|
|
||||||
"size": "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "AppIcon~ios-marketing.png",
|
|
||||||
"idiom": "ios-marketing",
|
|
||||||
"scale": "1x",
|
|
||||||
"size": "1024x1024"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": {
|
|
||||||
"author": "iconkitchen",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 349 B |
|
After Width: | Height: | Size: 701 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 489 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 701 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 942 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Conduit</string>
|
<string>iiEasy</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<string>zh-Hant</string>
|
<string>zh-Hant</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>conduit</string>
|
<string>iiEasy</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
@@ -64,6 +64,8 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>AppGroupId</key>
|
||||||
|
<string>group.app.cogwheel.conduit</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
@@ -76,13 +78,13 @@
|
|||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Conduit uses the camera to take photos or videos you choose to share in chats. For example, you can snap a photo of a document and attach it to a message.</string>
|
<string>iiEasy uses the camera to take photos or videos you choose to share in chats. For example, you can snap a photo of a document and attach it to a message.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Conduit uses the microphone to record voice messages and enable voice-to-text in chats. For example, when you hold the mic button in a conversation, we capture your speech to send as an audio message or transcript.</string>
|
<string>iiEasy uses the microphone to record voice messages and enable voice-to-text in chats. For example, when you hold the mic button in a conversation, we capture your speech to send as an audio message or transcript.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Conduit needs access to your photo library so you can select existing images or videos to share in chats. For example, you can pick a screenshot to include in a conversation.</string>
|
<string>iiEasy needs access to your photo library so you can select existing images or videos to share in chats. For example, you can pick a screenshot to include in a conversation.</string>
|
||||||
<key>NSSpeechRecognitionUsageDescription</key>
|
<key>NSSpeechRecognitionUsageDescription</key>
|
||||||
<string>Conduit uses on-device speech recognition so you can dictate messages hands‑free. Your speech is converted to text on your device when available.</string>
|
<string>iiEasy uses on-device speech recognition so you can dictate messages hands‑free. Your speech is converted to text on your device when available.</string>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
/* Localized versions of Info.plist keys */
|
||||||
CFBundleDisplayName = "Conduit";
|
CFBundleDisplayName = "iiEasy";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Ask Conduit</string>
|
<string>Ask iiEasy</string>
|
||||||
<!-- Uncomment below lines if you want to use a custom group id rather than the default. Set it in Build Settings -> User-Defined -->
|
<key>AppGroupId</key>
|
||||||
<!-- <key>AppGroupId</key>
|
<string>group.app.cogwheel.conduit</string>
|
||||||
<string>$(CUSTOM_GROUP_ID)</string> -->
|
|
||||||
|
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI Client
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI Client
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI Client
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: Cliente OpenWebUI
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit : Client OpenWebUI
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: Client OpenWebUI
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI 클라이언트
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI Client
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: Клиент OpenWebUI
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit: OpenWebUI 客户端
|
iiEasyWeb
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Conduit
|
iiEasyWeb
|
||||||
|
|||||||
@@ -226,6 +226,73 @@ class AuthStateManager extends _$AuthStateManager {
|
|||||||
// Fast path: trust token format to avoid blocking startup on network
|
// Fast path: trust token format to avoid blocking startup on network
|
||||||
final formatOk = _isValidTokenFormat(token);
|
final formatOk = _isValidTokenFormat(token);
|
||||||
if (formatOk) {
|
if (formatOk) {
|
||||||
|
// Network readiness gate: Wait for API to be reachable before
|
||||||
|
// transitioning to authenticated state. This prevents race conditions
|
||||||
|
// on cold starts with Cloudflare tunnels where the tunnel connection
|
||||||
|
// may not be established yet.
|
||||||
|
final apiReady = await _waitForApiReadiness();
|
||||||
|
if (!apiReady) {
|
||||||
|
DebugLogger.auth(
|
||||||
|
'API not reachable on cold start - keeping loading state',
|
||||||
|
);
|
||||||
|
// Keep loading state and retry via silent login if we have creds
|
||||||
|
final hasCreds = await storage.hasCredentials();
|
||||||
|
if (hasCreds) {
|
||||||
|
DebugLogger.auth(
|
||||||
|
'Has credentials - attempting silent login after API ready',
|
||||||
|
);
|
||||||
|
// Schedule a delayed retry that will wait for network.
|
||||||
|
// Allow time for network stack to stabilize after initial failure.
|
||||||
|
unawaited(
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||||
|
if (!ref.mounted) return;
|
||||||
|
try {
|
||||||
|
final retryReady = await _waitForApiReadiness(
|
||||||
|
timeout: const Duration(seconds: 10),
|
||||||
|
);
|
||||||
|
if (!ref.mounted) return;
|
||||||
|
if (retryReady) {
|
||||||
|
await _performSilentLogin();
|
||||||
|
} else {
|
||||||
|
_update(
|
||||||
|
(current) => current.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
error: 'Unable to connect to server',
|
||||||
|
isLoading: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
if (!ref.mounted) return;
|
||||||
|
DebugLogger.error(
|
||||||
|
'delayed-retry-failed',
|
||||||
|
scope: 'auth/state',
|
||||||
|
error: e,
|
||||||
|
stackTrace: stack,
|
||||||
|
);
|
||||||
|
_update(
|
||||||
|
(current) => current.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
error: 'Connection retry failed',
|
||||||
|
isLoading: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// No credentials - show error
|
||||||
|
_update(
|
||||||
|
(current) => current.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
error: 'Unable to connect to server',
|
||||||
|
isLoading: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_update(
|
_update(
|
||||||
(current) => current.copyWith(
|
(current) => current.copyWith(
|
||||||
status: AuthStatus.authenticated,
|
status: AuthStatus.authenticated,
|
||||||
@@ -652,6 +719,61 @@ class AuthStateManager extends _$AuthStateManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for the API to be reachable (network readiness gate).
|
||||||
|
///
|
||||||
|
/// On cold starts with Cloudflare tunnels or other proxy setups, the network
|
||||||
|
/// connection may not be established immediately. This method performs a
|
||||||
|
/// health check with retries to ensure we don't show the wrong screen due to
|
||||||
|
/// a race condition between auth state initialization and network readiness.
|
||||||
|
///
|
||||||
|
/// Returns true if the API is reachable within the timeout, false otherwise.
|
||||||
|
Future<bool> _waitForApiReadiness({
|
||||||
|
Duration timeout = const Duration(seconds: 3),
|
||||||
|
Duration retryDelay = const Duration(milliseconds: 300),
|
||||||
|
}) async {
|
||||||
|
final stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
// First ensure the API service provider is available
|
||||||
|
await _ensureApiServiceAvailable(timeout: const Duration(seconds: 1));
|
||||||
|
|
||||||
|
while (stopwatch.elapsed < timeout) {
|
||||||
|
if (!ref.mounted) return false;
|
||||||
|
|
||||||
|
final api = ref.read(apiServiceProvider);
|
||||||
|
if (api == null) {
|
||||||
|
await Future.delayed(retryDelay);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use checkHealth which hits the /health endpoint
|
||||||
|
final healthy = await api.checkHealth();
|
||||||
|
if (healthy) {
|
||||||
|
DebugLogger.auth(
|
||||||
|
'API readiness confirmed in ${stopwatch.elapsedMilliseconds}ms',
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
DebugLogger.auth(
|
||||||
|
'API readiness check failed (${stopwatch.elapsedMilliseconds}ms): $e',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait before retrying
|
||||||
|
if (stopwatch.elapsed + retryDelay < timeout) {
|
||||||
|
await Future.delayed(retryDelay);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugLogger.auth(
|
||||||
|
'API readiness timed out after ${stopwatch.elapsedMilliseconds}ms',
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform silent auto-login with saved credentials
|
/// Perform silent auto-login with saved credentials
|
||||||
Future<bool> silentLogin() async {
|
Future<bool> silentLogin() async {
|
||||||
// Coalesce concurrent calls (e.g., UI + interceptor retry)
|
// Coalesce concurrent calls (e.g., UI + interceptor retry)
|
||||||
|
|||||||
@@ -794,45 +794,67 @@ class ApiService {
|
|||||||
DebugLogger.log('settings-ok', scope: 'api/user-settings');
|
DebugLogger.log('settings-ok', scope: 'api/user-settings');
|
||||||
|
|
||||||
final data = response.data;
|
final data = response.data;
|
||||||
if (data is! Map<String, dynamic>) {
|
if (data is Map<String, dynamic>) {
|
||||||
DebugLogger.warning(
|
// Extract default model from ui.models array
|
||||||
'settings-format',
|
final ui = data['ui'];
|
||||||
scope: 'api/user-settings',
|
if (ui is Map<String, dynamic>) {
|
||||||
data: {'type': data.runtimeType},
|
final models = ui['models'];
|
||||||
);
|
if (models is List && models.isNotEmpty) {
|
||||||
return null;
|
// Return the first model in the user's preferred models list
|
||||||
}
|
final defaultModel = models.first.toString();
|
||||||
|
DebugLogger.log(
|
||||||
// Extract default model from ui.models array
|
'default-model',
|
||||||
final ui = data['ui'];
|
scope: 'api/user-settings',
|
||||||
if (ui is Map<String, dynamic>) {
|
data: {'id': defaultModel},
|
||||||
final models = ui['models'];
|
);
|
||||||
if (models is List && models.isNotEmpty) {
|
return defaultModel;
|
||||||
// Return the first model in the user's preferred models list
|
}
|
||||||
final defaultModel = models.first.toString();
|
|
||||||
DebugLogger.log(
|
|
||||||
'default-model',
|
|
||||||
scope: 'api/user-settings',
|
|
||||||
data: {'id': defaultModel},
|
|
||||||
);
|
|
||||||
return defaultModel;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.warning('default-model-missing', scope: 'api/user-settings');
|
// Fallback: user has no default model configured, pick first available
|
||||||
return null;
|
// This fixes issue #353 where secondary accounts couldn't send messages
|
||||||
|
DebugLogger.log(
|
||||||
|
'default-model-fallback',
|
||||||
|
scope: 'api/user-settings',
|
||||||
|
);
|
||||||
|
return _getFirstAvailableModelId();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
DebugLogger.error(
|
DebugLogger.error(
|
||||||
'default-model-error',
|
'default-model-error',
|
||||||
scope: 'api/user-settings',
|
scope: 'api/user-settings',
|
||||||
error: e,
|
error: e,
|
||||||
);
|
);
|
||||||
// Do not call admin-only configs endpoint here; let the caller
|
// Attempt fallback even on error
|
||||||
// handle fallback (e.g., first available model from /api/models).
|
return _getFirstAvailableModelId();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the ID of the first available model, or null if none available.
|
||||||
|
///
|
||||||
|
/// Used as a fallback when user has no default model configured.
|
||||||
|
Future<String?> _getFirstAvailableModelId() async {
|
||||||
|
try {
|
||||||
|
final models = await getModels();
|
||||||
|
if (models.isNotEmpty) {
|
||||||
|
final fallbackId = models.first.id;
|
||||||
|
DebugLogger.log(
|
||||||
|
'default-model-fallback-selected',
|
||||||
|
scope: 'api/user-settings',
|
||||||
|
data: {'id': fallbackId},
|
||||||
|
);
|
||||||
|
return fallbackId;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
DebugLogger.error(
|
||||||
|
'default-model-fallback-failed',
|
||||||
|
scope: 'api/user-settings',
|
||||||
|
error: e,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Conversations - Updated to use correct OpenWebUI API
|
// Conversations - Updated to use correct OpenWebUI API
|
||||||
Future<List<Conversation>> getConversations({int? limit, int? skip}) async {
|
Future<List<Conversation>> getConversations({int? limit, int? skip}) async {
|
||||||
final pinnedFuture = _fetchChatCollection(
|
final pinnedFuture = _fetchChatCollection(
|
||||||
@@ -1498,7 +1520,12 @@ class ApiService {
|
|||||||
Future<Map<String, dynamic>> getUserSettings() async {
|
Future<Map<String, dynamic>> getUserSettings() async {
|
||||||
_traceApi('Fetching user settings');
|
_traceApi('Fetching user settings');
|
||||||
final response = await _dio.get('/api/v1/users/user/settings');
|
final response = await _dio.get('/api/v1/users/user/settings');
|
||||||
return response.data as Map<String, dynamic>;
|
final data = response.data;
|
||||||
|
// Handle null response from server (happens for new users with no settings)
|
||||||
|
if (data is Map<String, dynamic>) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateUserSettings(Map<String, dynamic> settings) async {
|
Future<void> updateUserSettings(Map<String, dynamic> settings) async {
|
||||||
|
|||||||
@@ -405,12 +405,7 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
|
|||||||
Widget _buildWelcomeSection() {
|
Widget _buildWelcomeSection() {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
BrandService.createBrandIcon(
|
BrandService.createLogoImage(size: 48, context: context),
|
||||||
size: 48,
|
|
||||||
useGradient: false,
|
|
||||||
addShadow: false,
|
|
||||||
context: context,
|
|
||||||
),
|
|
||||||
const SizedBox(height: Spacing.lg),
|
const SizedBox(height: Spacing.lg),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.signIn,
|
AppLocalizations.of(context)!.signIn,
|
||||||
|
|||||||
@@ -604,12 +604,7 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Brand logo
|
// Brand logo
|
||||||
BrandService.createBrandIcon(
|
BrandService.createLogoImage(size: 56, context: context),
|
||||||
size: 56,
|
|
||||||
useGradient: false,
|
|
||||||
addShadow: false,
|
|
||||||
context: context,
|
|
||||||
),
|
|
||||||
// Reviewer mode badge
|
// Reviewer mode badge
|
||||||
if (reviewerMode)
|
if (reviewerMode)
|
||||||
Positioned(
|
Positioned(
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ class TextToSpeechService {
|
|||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await _eventSubscription?.cancel();
|
await _eventSubscription?.cancel();
|
||||||
_eventSubscription = null;
|
_eventSubscription = null;
|
||||||
|
|
||||||
|
// Reset the singleton state for next session
|
||||||
|
await TtsManager.instance.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates TTS settings.
|
/// Updates TTS settings.
|
||||||
|
|||||||
@@ -376,6 +376,28 @@ class TtsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets the manager state for a new session.
|
||||||
|
///
|
||||||
|
/// Call this between voice calls to ensure clean state. This clears
|
||||||
|
/// playback buffers and resets session tracking without destroying
|
||||||
|
/// the singleton instance.
|
||||||
|
Future<void> reset() async {
|
||||||
|
await stop();
|
||||||
|
|
||||||
|
// Reset playback state
|
||||||
|
_resetPlaybackState();
|
||||||
|
_activeSession = null;
|
||||||
|
_sessionCounter = 0;
|
||||||
|
|
||||||
|
// Reset server audio buffer
|
||||||
|
_serverAudioBuffer.clear();
|
||||||
|
_serverWaitingForNext = false;
|
||||||
|
|
||||||
|
// Reset cached voice defaults so they're refetched if needed
|
||||||
|
_serverDefaultVoice = null;
|
||||||
|
_serverDefaultVoiceFuture = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Disposes the manager and releases resources.
|
/// Disposes the manager and releases resources.
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await stop();
|
await stop();
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ class VoiceCallService {
|
|||||||
_activeAssistantMessageId = null;
|
_activeAssistantMessageId = null;
|
||||||
_responseCompleted = false;
|
_responseCompleted = false;
|
||||||
_listeningSuspendedForSpeech = false;
|
_listeningSuspendedForSpeech = false;
|
||||||
_resetServerAudio(stopPlayback: true);
|
await _resetServerAudio(stopPlayback: true);
|
||||||
|
|
||||||
if (_pauseReasons.isNotEmpty) {
|
if (_pauseReasons.isNotEmpty) {
|
||||||
_listeningPaused = true;
|
_listeningPaused = true;
|
||||||
@@ -584,7 +584,11 @@ class VoiceCallService {
|
|||||||
_speechQueue.clear();
|
_speechQueue.clear();
|
||||||
_enqueuedSentenceCount = 0;
|
_enqueuedSentenceCount = 0;
|
||||||
_responseCompleted = false;
|
_responseCompleted = false;
|
||||||
_resetServerAudio(stopPlayback: true);
|
// Fire-and-forget: This is a synchronous event handler where blocking
|
||||||
|
// would delay socket event processing. The audio player stop is fast
|
||||||
|
// and race conditions are acceptable here since new playback will
|
||||||
|
// wait for this session to complete anyway.
|
||||||
|
unawaited(_resetServerAudio(stopPlayback: true));
|
||||||
if (_isSpeaking) {
|
if (_isSpeaking) {
|
||||||
_isSpeaking = false;
|
_isSpeaking = false;
|
||||||
unawaited(_tts.stop());
|
unawaited(_tts.stop());
|
||||||
@@ -749,14 +753,14 @@ class VoiceCallService {
|
|||||||
_maybeResumeListeningAfterSpeech();
|
_maybeResumeListeningAfterSpeech();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resetServerAudio({bool stopPlayback = false}) {
|
Future<void> _resetServerAudio({bool stopPlayback = false}) async {
|
||||||
_serverAudioBuffer.clear();
|
_serverAudioBuffer.clear();
|
||||||
_pendingServerAudioFetches = 0;
|
_pendingServerAudioFetches = 0;
|
||||||
_serverAudioSession++;
|
_serverAudioSession++;
|
||||||
_nextServerChunkId = 0;
|
_nextServerChunkId = 0;
|
||||||
_nextServerPlaybackId = 0;
|
_nextServerPlaybackId = 0;
|
||||||
if (stopPlayback) {
|
if (stopPlayback) {
|
||||||
unawaited(_serverAudioPlayer.stop());
|
await _serverAudioPlayer.stop();
|
||||||
_isSpeaking = false;
|
_isSpeaking = false;
|
||||||
}
|
}
|
||||||
_serverPipelineActive = false;
|
_serverPipelineActive = false;
|
||||||
@@ -819,7 +823,7 @@ class VoiceCallService {
|
|||||||
if (_isDisposed) return;
|
if (_isDisposed) return;
|
||||||
_isSpeaking = false;
|
_isSpeaking = false;
|
||||||
_speechQueue.clear();
|
_speechQueue.clear();
|
||||||
_resetServerAudio(stopPlayback: true);
|
unawaited(_resetServerAudio(stopPlayback: true));
|
||||||
_listeningSuspendedForSpeech = false;
|
_listeningSuspendedForSpeech = false;
|
||||||
_updateState(VoiceCallState.error);
|
_updateState(VoiceCallState.error);
|
||||||
// Try to recover by restarting listening
|
// Try to recover by restarting listening
|
||||||
@@ -865,7 +869,7 @@ class VoiceCallService {
|
|||||||
_listeningSuspendedForSpeech = false;
|
_listeningSuspendedForSpeech = false;
|
||||||
_activeAssistantMessageId = null;
|
_activeAssistantMessageId = null;
|
||||||
_isSpeaking = false;
|
_isSpeaking = false;
|
||||||
_resetServerAudio(stopPlayback: true);
|
await _resetServerAudio(stopPlayback: true);
|
||||||
_updateState(VoiceCallState.disconnected);
|
_updateState(VoiceCallState.disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -911,7 +915,7 @@ class VoiceCallService {
|
|||||||
_enqueuedSentenceCount = 0;
|
_enqueuedSentenceCount = 0;
|
||||||
_responseCompleted = false;
|
_responseCompleted = false;
|
||||||
_listeningSuspendedForSpeech = false;
|
_listeningSuspendedForSpeech = false;
|
||||||
_resetServerAudio(stopPlayback: true);
|
await _resetServerAudio(stopPlayback: true);
|
||||||
await _tts.stop();
|
await _tts.stop();
|
||||||
_isSpeaking = false;
|
_isSpeaking = false;
|
||||||
_accumulatedResponse = '';
|
_accumulatedResponse = '';
|
||||||
@@ -985,7 +989,7 @@ class VoiceCallService {
|
|||||||
_enqueuedSentenceCount = 0;
|
_enqueuedSentenceCount = 0;
|
||||||
_responseCompleted = false;
|
_responseCompleted = false;
|
||||||
_listeningSuspendedForSpeech = false;
|
_listeningSuspendedForSpeech = false;
|
||||||
_resetServerAudio(stopPlayback: true);
|
unawaited(_resetServerAudio(stopPlayback: true));
|
||||||
pauseListening(reason: VoiceCallPauseReason.mute);
|
pauseListening(reason: VoiceCallPauseReason.mute);
|
||||||
} else {
|
} else {
|
||||||
resumeListening(reason: VoiceCallPauseReason.mute);
|
resumeListening(reason: VoiceCallPauseReason.mute);
|
||||||
@@ -1006,7 +1010,7 @@ class VoiceCallService {
|
|||||||
_callKitEventSubscription = null;
|
_callKitEventSubscription = null;
|
||||||
_socketSubscription?.dispose();
|
_socketSubscription?.dispose();
|
||||||
|
|
||||||
_voiceInput.dispose();
|
await _voiceInput.dispose();
|
||||||
await _tts.dispose();
|
await _tts.dispose();
|
||||||
await _serverAudioStateSub?.cancel();
|
await _serverAudioStateSub?.cancel();
|
||||||
await _serverAudioPlayer.dispose();
|
await _serverAudioPlayer.dispose();
|
||||||
@@ -1029,7 +1033,7 @@ class VoiceCallService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@riverpod
|
||||||
VoiceCallService voiceCallService(Ref ref) {
|
VoiceCallService voiceCallService(Ref ref) {
|
||||||
final voiceInput = ref.watch(voiceInputServiceProvider);
|
final voiceInput = ref.watch(voiceInputServiceProvider);
|
||||||
final api = ref.watch(apiServiceProvider);
|
final api = ref.watch(apiServiceProvider);
|
||||||
|
|||||||
@@ -1026,12 +1026,12 @@ class VoiceInputService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
Future<void> dispose() async {
|
||||||
stopListening();
|
await stopListening();
|
||||||
unawaited(_disposeVadHandler());
|
await _disposeVadHandler();
|
||||||
unawaited(_microphonePermissionProbe.dispose());
|
await _microphonePermissionProbe.dispose();
|
||||||
try {
|
try {
|
||||||
_speech.stop();
|
await _speech.stop();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../../shared/theme/theme_extensions.dart';
|
import '../../../shared/theme/theme_extensions.dart';
|
||||||
|
import '../../../shared/widgets/ii_easy_loading_logo.dart';
|
||||||
|
|
||||||
class SplashLauncherPage extends StatelessWidget {
|
class SplashLauncherPage extends StatelessWidget {
|
||||||
const SplashLauncherPage({super.key});
|
const SplashLauncherPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final isDark = context.conduitTheme.isDark;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: context.conduitTheme.surfaceBackground,
|
backgroundColor: isDark
|
||||||
body: Center(
|
? const Color(0xFF0A0A0A)
|
||||||
child: SizedBox(
|
: Colors.white,
|
||||||
width: 28,
|
body: IiEasyLoadingLogo(isDark: isDark),
|
||||||
height: 28,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2.5,
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
context.conduitTheme.loadingIndicator,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ import '../../../shared/widgets/model_avatar.dart';
|
|||||||
/// Profile page (You tab) showing user info and main actions
|
/// Profile page (You tab) showing user info and main actions
|
||||||
/// Enhanced with production-grade design tokens for better cohesion
|
/// Enhanced with production-grade design tokens for better cohesion
|
||||||
class ProfilePage extends ConsumerWidget {
|
class ProfilePage extends ConsumerWidget {
|
||||||
static const _githubSponsorsUrl = 'https://github.com/sponsors/cogwheel0';
|
|
||||||
static const _buyMeACoffeeUrl = 'https://www.buymeacoffee.com/cogwheel0';
|
|
||||||
|
|
||||||
const ProfilePage({super.key});
|
const ProfilePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -117,113 +114,10 @@ class ProfilePage extends ConsumerWidget {
|
|||||||
_buildProfileHeader(context, userData, api),
|
_buildProfileHeader(context, userData, api),
|
||||||
const SizedBox(height: Spacing.xl),
|
const SizedBox(height: Spacing.xl),
|
||||||
_buildAccountSection(context, ref),
|
_buildAccountSection(context, ref),
|
||||||
const SizedBox(height: Spacing.xl),
|
|
||||||
_buildSupportSection(context),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSupportSection(BuildContext context) {
|
|
||||||
final theme = context.conduitTheme;
|
|
||||||
final textTheme =
|
|
||||||
theme.bodySmall?.copyWith(
|
|
||||||
color: theme.sidebarForeground.withValues(alpha: 0.75),
|
|
||||||
) ??
|
|
||||||
TextStyle(color: theme.sidebarForeground.withValues(alpha: 0.75));
|
|
||||||
|
|
||||||
final supportTiles = [
|
|
||||||
_buildSupportOption(
|
|
||||||
context,
|
|
||||||
icon: UiUtils.platformIcon(
|
|
||||||
ios: CupertinoIcons.gift,
|
|
||||||
android: Icons.coffee,
|
|
||||||
),
|
|
||||||
title: AppLocalizations.of(context)!.buyMeACoffeeTitle,
|
|
||||||
subtitle: AppLocalizations.of(context)!.buyMeACoffeeSubtitle,
|
|
||||||
url: _buyMeACoffeeUrl,
|
|
||||||
color: theme.warning,
|
|
||||||
),
|
|
||||||
_buildSupportOption(
|
|
||||||
context,
|
|
||||||
icon: UiUtils.platformIcon(
|
|
||||||
ios: CupertinoIcons.heart,
|
|
||||||
android: Icons.favorite_border,
|
|
||||||
),
|
|
||||||
title: AppLocalizations.of(context)!.githubSponsorsTitle,
|
|
||||||
subtitle: AppLocalizations.of(context)!.githubSponsorsSubtitle,
|
|
||||||
url: _githubSponsorsUrl,
|
|
||||||
color: theme.success,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.supportConduit,
|
|
||||||
style: theme.headingSmall?.copyWith(color: theme.sidebarForeground),
|
|
||||||
),
|
|
||||||
const SizedBox(height: Spacing.xs),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.supportConduitSubtitle,
|
|
||||||
style: textTheme,
|
|
||||||
),
|
|
||||||
const SizedBox(height: Spacing.sm),
|
|
||||||
for (var i = 0; i < supportTiles.length; i++) ...[
|
|
||||||
supportTiles[i],
|
|
||||||
if (i != supportTiles.length - 1) const SizedBox(height: Spacing.md),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSupportOption(
|
|
||||||
BuildContext context, {
|
|
||||||
required IconData icon,
|
|
||||||
required String title,
|
|
||||||
required String subtitle,
|
|
||||||
required String url,
|
|
||||||
required Color color,
|
|
||||||
}) {
|
|
||||||
final theme = context.conduitTheme;
|
|
||||||
return _ProfileSettingTile(
|
|
||||||
onTap: () => _openExternalLink(context, url),
|
|
||||||
leading: _buildIconBadge(context, icon, color: color),
|
|
||||||
title: title,
|
|
||||||
subtitle: subtitle,
|
|
||||||
trailing: Icon(
|
|
||||||
UiUtils.platformIcon(
|
|
||||||
ios: CupertinoIcons.arrow_up_right,
|
|
||||||
android: Icons.open_in_new,
|
|
||||||
),
|
|
||||||
color: theme.iconSecondary,
|
|
||||||
size: IconSize.small,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _openExternalLink(BuildContext context, String url) async {
|
|
||||||
try {
|
|
||||||
final launched = await launchUrlString(
|
|
||||||
url,
|
|
||||||
mode: LaunchMode.externalApplication,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!launched && context.mounted) {
|
|
||||||
UiUtils.showMessage(
|
|
||||||
context,
|
|
||||||
AppLocalizations.of(context)!.errorMessage,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} on PlatformException catch (_) {
|
|
||||||
if (!context.mounted) return;
|
|
||||||
UiUtils.showMessage(context, AppLocalizations.of(context)!.errorMessage);
|
|
||||||
} catch (_) {
|
|
||||||
if (!context.mounted) return;
|
|
||||||
UiUtils.showMessage(context, AppLocalizations.of(context)!.errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildProfileHeader(
|
Widget _buildProfileHeader(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic user,
|
dynamic user,
|
||||||
@@ -551,8 +445,8 @@ class ProfilePage extends ConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final info = await PackageInfo.fromPlatform();
|
final info = await PackageInfo.fromPlatform();
|
||||||
// Update dialog with dynamic version each time
|
// Update dialog with dynamic version each time
|
||||||
// GitHub repo URL source of truth
|
// Developer / app info URL
|
||||||
const githubUrl = 'https://github.com/cogwheel0/conduit';
|
const githubUrl = 'https://iiEasy.ru';
|
||||||
|
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
@@ -606,6 +500,13 @@ class ProfilePage extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: Spacing.sm),
|
||||||
|
Text(
|
||||||
|
'Based on Conduit',
|
||||||
|
style: ctx.conduitTheme.bodySmall?.copyWith(
|
||||||
|
color: ctx.sidebarTheme.foreground.withValues(alpha: 0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "de",
|
"@@locale": "de",
|
||||||
"appTitle": "Conduit",
|
"appTitle": "iiEasy",
|
||||||
|
"appSlogan": "Zukunft. Einfach.",
|
||||||
"retry": "Erneut versuchen",
|
"retry": "Erneut versuchen",
|
||||||
"back": "Zurück",
|
"back": "Zurück",
|
||||||
"you": "Du",
|
"you": "Du",
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
"description": "Untertitel mit den verfügbaren Aktionen, wenn der Server nicht erreichbar ist"
|
"description": "Untertitel mit den verfügbaren Aktionen, wenn der Server nicht erreichbar ist"
|
||||||
},
|
},
|
||||||
"account": "Konto",
|
"account": "Konto",
|
||||||
"supportConduit": "Conduit unterstützen",
|
"supportConduit": "iiEasy unterstützen",
|
||||||
"supportConduitSubtitle": "Hilf, die Weiterentwicklung und neue Funktionen zu finanzieren.",
|
"supportConduitSubtitle": "Unterstütze iiEasy durch Finanzierung der Weiterentwicklung.",
|
||||||
"githubSponsorsTitle": "GitHub Sponsors",
|
"githubSponsorsTitle": "GitHub Sponsors",
|
||||||
"githubSponsorsSubtitle": "Werde monatliche*r Sponsor*in und unterstütze die Roadmap.",
|
"githubSponsorsSubtitle": "Werde monatliche*r Sponsor*in und unterstütze die Roadmap.",
|
||||||
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"signInWithToken": "Mit Token anmelden",
|
"signInWithToken": "Mit Token anmelden",
|
||||||
"connectToServer": "Mit Server verbinden",
|
"connectToServer": "Mit Server verbinden",
|
||||||
"enterServerAddress": "Gib die Adresse deines Open-WebUI-Servers ein, um zu beginnen",
|
"enterServerAddress": "Gib die Adresse deines iiEasyWeb-Servers ein, um zu beginnen",
|
||||||
"serverUrl": "Server-URL",
|
"serverUrl": "Server-URL",
|
||||||
"serverUrlHint": "https://dein-server.com",
|
"serverUrlHint": "https://dein-server.com",
|
||||||
"enterServerUrlSemantic": "Gib deine Server-URL oder IP-Adresse ein",
|
"enterServerUrlSemantic": "Gib deine Server-URL oder IP-Adresse ein",
|
||||||
@@ -116,7 +117,7 @@
|
|||||||
"voicePromptTapStart": "Tippe auf \"Starten\", um zu beginnen",
|
"voicePromptTapStart": "Tippe auf \"Starten\", um zu beginnen",
|
||||||
"voiceActionStop": "Stopp",
|
"voiceActionStop": "Stopp",
|
||||||
"voiceActionStart": "Starten",
|
"voiceActionStart": "Starten",
|
||||||
"messageHintText": "Frag Conduit",
|
"messageHintText": "Frag iiEasy",
|
||||||
"stopGenerating": "Generierung stoppen",
|
"stopGenerating": "Generierung stoppen",
|
||||||
"codeCopiedToClipboard": "Code in die Zwischenablage kopiert.",
|
"codeCopiedToClipboard": "Code in die Zwischenablage kopiert.",
|
||||||
"send": "Senden",
|
"send": "Senden",
|
||||||
@@ -204,7 +205,7 @@
|
|||||||
"deleteFolderMessage": "Dieser Ordner und seine Zuordnungen werden entfernt.",
|
"deleteFolderMessage": "Dieser Ordner und seine Zuordnungen werden entfernt.",
|
||||||
"failedToDeleteFolder": "Ordner konnte nicht gelöscht werden",
|
"failedToDeleteFolder": "Ordner konnte nicht gelöscht werden",
|
||||||
"aboutApp": "Über",
|
"aboutApp": "Über",
|
||||||
"aboutAppSubtitle": "Conduit Informationen und Links",
|
"aboutAppSubtitle": "iiEasy Informationen und Links",
|
||||||
"web": "Web",
|
"web": "Web",
|
||||||
"imageGen": "Bild-Gen",
|
"imageGen": "Bild-Gen",
|
||||||
"pinned": "Angeheftet",
|
"pinned": "Angeheftet",
|
||||||
@@ -280,7 +281,7 @@
|
|||||||
"themeLight": "Hell",
|
"themeLight": "Hell",
|
||||||
"currentlyUsingDarkTheme": "Aktuell dunkles Thema",
|
"currentlyUsingDarkTheme": "Aktuell dunkles Thema",
|
||||||
"currentlyUsingLightTheme": "Aktuell helles Thema",
|
"currentlyUsingLightTheme": "Aktuell helles Thema",
|
||||||
"aboutConduit": "Über Conduit",
|
"aboutConduit": "Über iiEasy",
|
||||||
"versionLabel": "Version: {version} ({build})",
|
"versionLabel": "Version: {version} ({build})",
|
||||||
"@versionLabel": {
|
"@versionLabel": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -317,7 +318,7 @@
|
|||||||
"androidAssistantTitle": "Android digital assistant",
|
"androidAssistantTitle": "Android digital assistant",
|
||||||
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
||||||
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
||||||
"androidAssistantNewChatOption": "Open Conduit with a new chat",
|
"androidAssistantNewChatOption": "Open iiEasy with a new chat",
|
||||||
"androidAssistantVoiceCallOption": "Start a voice call",
|
"androidAssistantVoiceCallOption": "Start a voice call",
|
||||||
"sttSettings": "Sprache zu Text",
|
"sttSettings": "Sprache zu Text",
|
||||||
"sttEngineLabel": "Erkennungs-Engine",
|
"sttEngineLabel": "Erkennungs-Engine",
|
||||||
@@ -650,11 +651,11 @@
|
|||||||
"@nextLabel": {
|
"@nextLabel": {
|
||||||
"description": "Label for navigating to the next item."
|
"description": "Label for navigating to the next item."
|
||||||
},
|
},
|
||||||
"themePaletteConduitLabel": "Conduit",
|
"themePaletteConduitLabel": "iiEasy",
|
||||||
"@themePaletteConduitLabel": {
|
"@themePaletteConduitLabel": {
|
||||||
"description": "Palette name for the default Conduit theme."
|
"description": "Palette name for the default Conduit theme."
|
||||||
},
|
},
|
||||||
"themePaletteConduitDescription": "Schlichtes neutrales Design für Conduit.",
|
"themePaletteConduitDescription": "Schlichtes neutrales Design für iiEasy.",
|
||||||
"@themePaletteConduitDescription": {
|
"@themePaletteConduitDescription": {
|
||||||
"description": "Description of the Conduit palette."
|
"description": "Description of the Conduit palette."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "en",
|
"@@locale": "en",
|
||||||
"appTitle": "Conduit",
|
"appTitle": "iiEasy",
|
||||||
"@appTitle": {
|
"@appTitle": {
|
||||||
"description": "Application name displayed in the app and OS UI."
|
"description": "Application name displayed in the app and OS UI."
|
||||||
},
|
},
|
||||||
|
"appSlogan": "Future. Simple.",
|
||||||
|
"@appSlogan": {
|
||||||
|
"description": "Brand slogan shown on loading/splash."
|
||||||
|
},
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
"@retry": {
|
"@retry": {
|
||||||
"description": "Button label to try an action again."
|
"description": "Button label to try an action again."
|
||||||
@@ -36,11 +40,11 @@
|
|||||||
"@account": {
|
"@account": {
|
||||||
"description": "Section header for account-related options."
|
"description": "Section header for account-related options."
|
||||||
},
|
},
|
||||||
"supportConduit": "Support Conduit",
|
"supportConduit": "Support iiEasy",
|
||||||
"@supportConduit": {
|
"@supportConduit": {
|
||||||
"description": "Section header inviting the user to financially support the project."
|
"description": "Section header inviting the user to financially support the project."
|
||||||
},
|
},
|
||||||
"supportConduitSubtitle": "Keep Conduit independent by funding ongoing development.",
|
"supportConduitSubtitle": "Keep iiEasy independent by funding ongoing development.",
|
||||||
"@supportConduitSubtitle": {
|
"@supportConduitSubtitle": {
|
||||||
"description": "Subtitle explaining why donations are helpful."
|
"description": "Subtitle explaining why donations are helpful."
|
||||||
},
|
},
|
||||||
@@ -232,7 +236,7 @@
|
|||||||
"@connectToServer": {
|
"@connectToServer": {
|
||||||
"description": "Call-to-action button for server connection."
|
"description": "Call-to-action button for server connection."
|
||||||
},
|
},
|
||||||
"enterServerAddress": "Enter your Open-WebUI server address to get started",
|
"enterServerAddress": "Enter your iiEasyWeb server address to get started",
|
||||||
"@enterServerAddress": {
|
"@enterServerAddress": {
|
||||||
"description": "Instruction telling user to provide server URL to begin."
|
"description": "Instruction telling user to provide server URL to begin."
|
||||||
},
|
},
|
||||||
@@ -554,7 +558,7 @@
|
|||||||
"@voiceCallErrorHelp": {
|
"@voiceCallErrorHelp": {
|
||||||
"description": "Guidance shown when the voice call encounters an error."
|
"description": "Guidance shown when the voice call encounters an error."
|
||||||
},
|
},
|
||||||
"messageHintText": "Ask Conduit",
|
"messageHintText": "Ask iiEasy",
|
||||||
"@messageHintText": {
|
"@messageHintText": {
|
||||||
"description": "Short placeholder text in the message input."
|
"description": "Short placeholder text in the message input."
|
||||||
},
|
},
|
||||||
@@ -920,7 +924,7 @@
|
|||||||
"@aboutApp": {
|
"@aboutApp": {
|
||||||
"description": "Settings tile title to view app information."
|
"description": "Settings tile title to view app information."
|
||||||
},
|
},
|
||||||
"aboutAppSubtitle": "Conduit information and links",
|
"aboutAppSubtitle": "iiEasy information and links",
|
||||||
"@aboutAppSubtitle": {
|
"@aboutAppSubtitle": {
|
||||||
"description": "Subtitle/description for the About section."
|
"description": "Subtitle/description for the About section."
|
||||||
},
|
},
|
||||||
@@ -1173,11 +1177,11 @@
|
|||||||
"@themePalette": {
|
"@themePalette": {
|
||||||
"description": "Title for selecting the app color palette."
|
"description": "Title for selecting the app color palette."
|
||||||
},
|
},
|
||||||
"themePaletteConduitLabel": "Conduit",
|
"themePaletteConduitLabel": "iiEasy",
|
||||||
"@themePaletteConduitLabel": {
|
"@themePaletteConduitLabel": {
|
||||||
"description": "Palette name for the default Conduit theme."
|
"description": "Palette name for the default Conduit theme."
|
||||||
},
|
},
|
||||||
"themePaletteConduitDescription": "Clean neutral theme designed for Conduit.",
|
"themePaletteConduitDescription": "Clean neutral theme designed for iiEasy.",
|
||||||
"@themePaletteConduitDescription": {
|
"@themePaletteConduitDescription": {
|
||||||
"description": "Description of the Conduit palette."
|
"description": "Description of the Conduit palette."
|
||||||
},
|
},
|
||||||
@@ -1225,7 +1229,7 @@
|
|||||||
"@currentlyUsingLightTheme": {
|
"@currentlyUsingLightTheme": {
|
||||||
"description": "Status text indicating light theme is active."
|
"description": "Status text indicating light theme is active."
|
||||||
},
|
},
|
||||||
"aboutConduit": "About Conduit",
|
"aboutConduit": "About iiEasy",
|
||||||
"@aboutConduit": {
|
"@aboutConduit": {
|
||||||
"description": "Dialog title for app information."
|
"description": "Dialog title for app information."
|
||||||
},
|
},
|
||||||
@@ -1241,7 +1245,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"githubRepository": "GitHub Repository",
|
"githubRepository": "iiEasy.ru",
|
||||||
"@githubRepository": {
|
"@githubRepository": {
|
||||||
"description": "Link label pointing to the app repository."
|
"description": "Link label pointing to the app repository."
|
||||||
},
|
},
|
||||||
@@ -1325,7 +1329,7 @@
|
|||||||
"@androidAssistantOverlayOption": {
|
"@androidAssistantOverlayOption": {
|
||||||
"description": "Option label for keeping the current assistant overlay."
|
"description": "Option label for keeping the current assistant overlay."
|
||||||
},
|
},
|
||||||
"androidAssistantNewChatOption": "Open Conduit with a new chat",
|
"androidAssistantNewChatOption": "Open iiEasy with a new chat",
|
||||||
"@androidAssistantNewChatOption": {
|
"@androidAssistantNewChatOption": {
|
||||||
"description": "Option label for opening the app to a fresh chat from the assistant trigger."
|
"description": "Option label for opening the app to a fresh chat from the assistant trigger."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "es",
|
"@@locale": "es",
|
||||||
"appTitle": "Conduit",
|
"appTitle": "iiEasy",
|
||||||
|
"appSlogan": "Futuro. Simple.",
|
||||||
"retry": "Reintentar",
|
"retry": "Reintentar",
|
||||||
"back": "Atrás",
|
"back": "Atrás",
|
||||||
"you": "Tú",
|
"you": "Tú",
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
"description": "Subtítulo que explica las acciones disponibles cuando no se puede acceder al servidor"
|
"description": "Subtítulo que explica las acciones disponibles cuando no se puede acceder al servidor"
|
||||||
},
|
},
|
||||||
"account": "Cuenta",
|
"account": "Cuenta",
|
||||||
"supportConduit": "Apoyar Conduit",
|
"supportConduit": "Apoyar iiEasy",
|
||||||
"supportConduitSubtitle": "Mantén Conduit independiente financiando el desarrollo continuo.",
|
"supportConduitSubtitle": "Mantén iiEasy independiente financiando el desarrollo continuo.",
|
||||||
"githubSponsorsTitle": "GitHub Sponsors",
|
"githubSponsorsTitle": "GitHub Sponsors",
|
||||||
"githubSponsorsSubtitle": "Conviértete en un patrocinador recurrente para financiar elementos del roadmap.",
|
"githubSponsorsSubtitle": "Conviértete en un patrocinador recurrente para financiar elementos del roadmap.",
|
||||||
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
"signInWithToken": "Iniciar sesión con token",
|
"signInWithToken": "Iniciar sesión con token",
|
||||||
"connectToServer": "Conectar al servidor",
|
"connectToServer": "Conectar al servidor",
|
||||||
"enterServerAddress": "Ingresa la dirección de tu servidor Open-WebUI para comenzar",
|
"enterServerAddress": "Ingresa la dirección de tu servidor iiEasyWeb para comenzar",
|
||||||
"serverUrl": "URL del servidor",
|
"serverUrl": "URL del servidor",
|
||||||
"serverUrlHint": "https://tu-servidor.com",
|
"serverUrlHint": "https://tu-servidor.com",
|
||||||
"enterServerUrlSemantic": "Ingresa la URL o dirección IP de tu servidor",
|
"enterServerUrlSemantic": "Ingresa la URL o dirección IP de tu servidor",
|
||||||
@@ -116,7 +117,7 @@
|
|||||||
"voicePromptTapStart": "Toca Iniciar para comenzar",
|
"voicePromptTapStart": "Toca Iniciar para comenzar",
|
||||||
"voiceActionStop": "Detener",
|
"voiceActionStop": "Detener",
|
||||||
"voiceActionStart": "Iniciar",
|
"voiceActionStart": "Iniciar",
|
||||||
"messageHintText": "Pregunta a Conduit",
|
"messageHintText": "Pregunta a iiEasy",
|
||||||
"stopGenerating": "Detener generación",
|
"stopGenerating": "Detener generación",
|
||||||
"codeCopiedToClipboard": "Código copiado al portapapeles.",
|
"codeCopiedToClipboard": "Código copiado al portapapeles.",
|
||||||
"send": "Enviar",
|
"send": "Enviar",
|
||||||
@@ -204,7 +205,7 @@
|
|||||||
"deleteFolderMessage": "Esta carpeta y sus referencias de asignación se eliminarán.",
|
"deleteFolderMessage": "Esta carpeta y sus referencias de asignación se eliminarán.",
|
||||||
"failedToDeleteFolder": "No se pudo eliminar la carpeta",
|
"failedToDeleteFolder": "No se pudo eliminar la carpeta",
|
||||||
"aboutApp": "Acerca de",
|
"aboutApp": "Acerca de",
|
||||||
"aboutAppSubtitle": "Información y enlaces de Conduit",
|
"aboutAppSubtitle": "Información y enlaces de iiEasy",
|
||||||
"web": "Web",
|
"web": "Web",
|
||||||
"imageGen": "Generación de imágenes",
|
"imageGen": "Generación de imágenes",
|
||||||
"pinned": "Anclado",
|
"pinned": "Anclado",
|
||||||
@@ -280,7 +281,7 @@
|
|||||||
"themeLight": "Claro",
|
"themeLight": "Claro",
|
||||||
"currentlyUsingDarkTheme": "Usando actualmente el tema oscuro",
|
"currentlyUsingDarkTheme": "Usando actualmente el tema oscuro",
|
||||||
"currentlyUsingLightTheme": "Usando actualmente el tema claro",
|
"currentlyUsingLightTheme": "Usando actualmente el tema claro",
|
||||||
"aboutConduit": "Acerca de Conduit",
|
"aboutConduit": "Acerca de iiEasy",
|
||||||
"versionLabel": "Versión: {version} ({build})",
|
"versionLabel": "Versión: {version} ({build})",
|
||||||
"@versionLabel": {
|
"@versionLabel": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -317,7 +318,7 @@
|
|||||||
"androidAssistantTitle": "Android digital assistant",
|
"androidAssistantTitle": "Android digital assistant",
|
||||||
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
||||||
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
||||||
"androidAssistantNewChatOption": "Open Conduit with a new chat",
|
"androidAssistantNewChatOption": "Open iiEasy with a new chat",
|
||||||
"androidAssistantVoiceCallOption": "Start a voice call",
|
"androidAssistantVoiceCallOption": "Start a voice call",
|
||||||
"sttSettings": "Voz a texto",
|
"sttSettings": "Voz a texto",
|
||||||
"sttEngineLabel": "Motor de reconocimiento",
|
"sttEngineLabel": "Motor de reconocimiento",
|
||||||
@@ -650,11 +651,11 @@
|
|||||||
"@nextLabel": {
|
"@nextLabel": {
|
||||||
"description": "Label for navigating to the next item."
|
"description": "Label for navigating to the next item."
|
||||||
},
|
},
|
||||||
"themePaletteConduitLabel": "Conduit",
|
"themePaletteConduitLabel": "iiEasy",
|
||||||
"@themePaletteConduitLabel": {
|
"@themePaletteConduitLabel": {
|
||||||
"description": "Palette name for the default Conduit theme."
|
"description": "Palette name for the default Conduit theme."
|
||||||
},
|
},
|
||||||
"themePaletteConduitDescription": "Tema neutro y limpio diseñado para Conduit.",
|
"themePaletteConduitDescription": "Tema neutro y limpio diseñado para iiEasy.",
|
||||||
"@themePaletteConduitDescription": {
|
"@themePaletteConduitDescription": {
|
||||||
"description": "Description of the Conduit palette."
|
"description": "Description of the Conduit palette."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "fr",
|
"@@locale": "fr",
|
||||||
"appTitle": "Conduit",
|
"appTitle": "iiEasy",
|
||||||
|
"appSlogan": "Avenir. Simple.",
|
||||||
"retry": "Réessayer",
|
"retry": "Réessayer",
|
||||||
"back": "Retour",
|
"back": "Retour",
|
||||||
"you": "Vous",
|
"you": "Vous",
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
"description": "Sous-titre expliquant les actions possibles quand le serveur est injoignable"
|
"description": "Sous-titre expliquant les actions possibles quand le serveur est injoignable"
|
||||||
},
|
},
|
||||||
"account": "Compte",
|
"account": "Compte",
|
||||||
"supportConduit": "Soutenir Conduit",
|
"supportConduit": "Soutenir iiEasy",
|
||||||
"supportConduitSubtitle": "Financez le développement continu et les nouvelles fonctionnalités.",
|
"supportConduitSubtitle": "Soutenez iiEasy en finançant le développement continu.",
|
||||||
"githubSponsorsTitle": "GitHub Sponsors",
|
"githubSponsorsTitle": "GitHub Sponsors",
|
||||||
"githubSponsorsSubtitle": "Devenez sponsor récurrent pour soutenir la feuille de route.",
|
"githubSponsorsSubtitle": "Devenez sponsor récurrent pour soutenir la feuille de route.",
|
||||||
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"signInWithToken": "Se connecter avec un jeton",
|
"signInWithToken": "Se connecter avec un jeton",
|
||||||
"connectToServer": "Se connecter au serveur",
|
"connectToServer": "Se connecter au serveur",
|
||||||
"enterServerAddress": "Saisissez l'adresse de votre serveur Open-WebUI pour commencer",
|
"enterServerAddress": "Saisissez l'adresse de votre serveur iiEasyWeb pour commencer",
|
||||||
"serverUrl": "URL du serveur",
|
"serverUrl": "URL du serveur",
|
||||||
"serverUrlHint": "https://votre-serveur.com",
|
"serverUrlHint": "https://votre-serveur.com",
|
||||||
"enterServerUrlSemantic": "Saisissez l'URL ou l'adresse IP de votre serveur",
|
"enterServerUrlSemantic": "Saisissez l'URL ou l'adresse IP de votre serveur",
|
||||||
@@ -116,7 +117,7 @@
|
|||||||
"voicePromptTapStart": "Appuyez sur \"Démarrer\" pour commencer",
|
"voicePromptTapStart": "Appuyez sur \"Démarrer\" pour commencer",
|
||||||
"voiceActionStop": "Arrêter",
|
"voiceActionStop": "Arrêter",
|
||||||
"voiceActionStart": "Démarrer",
|
"voiceActionStart": "Démarrer",
|
||||||
"messageHintText": "Demander à Conduit",
|
"messageHintText": "Demander à iiEasy",
|
||||||
"stopGenerating": "Arrêter la génération",
|
"stopGenerating": "Arrêter la génération",
|
||||||
"codeCopiedToClipboard": "Code copié dans le presse-papiers.",
|
"codeCopiedToClipboard": "Code copié dans le presse-papiers.",
|
||||||
"send": "Envoyer",
|
"send": "Envoyer",
|
||||||
@@ -204,7 +205,7 @@
|
|||||||
"deleteFolderMessage": "Ce dossier et ses associations seront supprimés.",
|
"deleteFolderMessage": "Ce dossier et ses associations seront supprimés.",
|
||||||
"failedToDeleteFolder": "Échec de la suppression du dossier",
|
"failedToDeleteFolder": "Échec de la suppression du dossier",
|
||||||
"aboutApp": "À propos",
|
"aboutApp": "À propos",
|
||||||
"aboutAppSubtitle": "Informations et liens Conduit",
|
"aboutAppSubtitle": "Informations et liens iiEasy",
|
||||||
"web": "Web",
|
"web": "Web",
|
||||||
"imageGen": "Gén. image",
|
"imageGen": "Gén. image",
|
||||||
"pinned": "Épinglé",
|
"pinned": "Épinglé",
|
||||||
@@ -280,7 +281,7 @@
|
|||||||
"themeLight": "Clair",
|
"themeLight": "Clair",
|
||||||
"currentlyUsingDarkTheme": "Thème sombre actuellement utilisé",
|
"currentlyUsingDarkTheme": "Thème sombre actuellement utilisé",
|
||||||
"currentlyUsingLightTheme": "Thème clair actuellement utilisé",
|
"currentlyUsingLightTheme": "Thème clair actuellement utilisé",
|
||||||
"aboutConduit": "À propos de Conduit",
|
"aboutConduit": "À propos de iiEasy",
|
||||||
"versionLabel": "Version : {version} ({build})",
|
"versionLabel": "Version : {version} ({build})",
|
||||||
"@versionLabel": {
|
"@versionLabel": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -317,7 +318,7 @@
|
|||||||
"androidAssistantTitle": "Android digital assistant",
|
"androidAssistantTitle": "Android digital assistant",
|
||||||
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
||||||
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
||||||
"androidAssistantNewChatOption": "Open Conduit with a new chat",
|
"androidAssistantNewChatOption": "Open iiEasy with a new chat",
|
||||||
"androidAssistantVoiceCallOption": "Start a voice call",
|
"androidAssistantVoiceCallOption": "Start a voice call",
|
||||||
"sttSettings": "Voix vers texte",
|
"sttSettings": "Voix vers texte",
|
||||||
"sttEngineLabel": "Moteur de reconnaissance",
|
"sttEngineLabel": "Moteur de reconnaissance",
|
||||||
@@ -650,11 +651,11 @@
|
|||||||
"@nextLabel": {
|
"@nextLabel": {
|
||||||
"description": "Label for navigating to the next item."
|
"description": "Label for navigating to the next item."
|
||||||
},
|
},
|
||||||
"themePaletteConduitLabel": "Conduit",
|
"themePaletteConduitLabel": "iiEasy",
|
||||||
"@themePaletteConduitLabel": {
|
"@themePaletteConduitLabel": {
|
||||||
"description": "Palette name for the default Conduit theme."
|
"description": "Palette name for the default Conduit theme."
|
||||||
},
|
},
|
||||||
"themePaletteConduitDescription": "Thème neutre et épuré conçu pour Conduit.",
|
"themePaletteConduitDescription": "Thème neutre et épuré conçu pour iiEasy.",
|
||||||
"@themePaletteConduitDescription": {
|
"@themePaletteConduitDescription": {
|
||||||
"description": "Description of the Conduit palette."
|
"description": "Description of the Conduit palette."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "it",
|
"@@locale": "it",
|
||||||
"appTitle": "Conduit",
|
"appTitle": "iiEasy",
|
||||||
|
"appSlogan": "Futuro. Semplice.",
|
||||||
"retry": "Riprova",
|
"retry": "Riprova",
|
||||||
"back": "Indietro",
|
"back": "Indietro",
|
||||||
"you": "Tu",
|
"you": "Tu",
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
"description": "Sottotitolo che spiega le azioni disponibili quando il server non è raggiungibile"
|
"description": "Sottotitolo che spiega le azioni disponibili quando il server non è raggiungibile"
|
||||||
},
|
},
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"supportConduit": "Sostieni Conduit",
|
"supportConduit": "Sostieni iiEasy",
|
||||||
"supportConduitSubtitle": "Mantieni Conduit indipendente finanziando lo sviluppo continuo.",
|
"supportConduitSubtitle": "Mantieni iiEasy indipendente finanziando lo sviluppo continuo.",
|
||||||
"githubSponsorsTitle": "GitHub Sponsors",
|
"githubSponsorsTitle": "GitHub Sponsors",
|
||||||
"githubSponsorsSubtitle": "Diventa sponsor ricorrente per supportare la roadmap.",
|
"githubSponsorsSubtitle": "Diventa sponsor ricorrente per supportare la roadmap.",
|
||||||
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
"buyMeACoffeeTitle": "Buy Me a Coffee",
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
"password": "Password",
|
"password": "Password",
|
||||||
"signInWithToken": "Accedi con token",
|
"signInWithToken": "Accedi con token",
|
||||||
"connectToServer": "Connetti al server",
|
"connectToServer": "Connetti al server",
|
||||||
"enterServerAddress": "Inserisci l'indirizzo del server Open-WebUI per iniziare",
|
"enterServerAddress": "Inserisci l'indirizzo del server iiEasyWeb per iniziare",
|
||||||
"serverUrl": "URL del server",
|
"serverUrl": "URL del server",
|
||||||
"serverUrlHint": "https://tuo-server.com",
|
"serverUrlHint": "https://tuo-server.com",
|
||||||
"enterServerUrlSemantic": "Inserisci l'URL o l'indirizzo IP del server",
|
"enterServerUrlSemantic": "Inserisci l'URL o l'indirizzo IP del server",
|
||||||
@@ -116,7 +117,7 @@
|
|||||||
"voicePromptTapStart": "Tocca \"Avvia\" per iniziare",
|
"voicePromptTapStart": "Tocca \"Avvia\" per iniziare",
|
||||||
"voiceActionStop": "Stop",
|
"voiceActionStop": "Stop",
|
||||||
"voiceActionStart": "Avvia",
|
"voiceActionStart": "Avvia",
|
||||||
"messageHintText": "Chiedi a Conduit",
|
"messageHintText": "Chiedi a iiEasy",
|
||||||
"stopGenerating": "Interrompi generazione",
|
"stopGenerating": "Interrompi generazione",
|
||||||
"codeCopiedToClipboard": "Codice copiato negli appunti.",
|
"codeCopiedToClipboard": "Codice copiato negli appunti.",
|
||||||
"send": "Invia",
|
"send": "Invia",
|
||||||
@@ -204,7 +205,7 @@
|
|||||||
"deleteFolderMessage": "Questa cartella e le sue associazioni verranno rimosse.",
|
"deleteFolderMessage": "Questa cartella e le sue associazioni verranno rimosse.",
|
||||||
"failedToDeleteFolder": "Impossibile eliminare la cartella",
|
"failedToDeleteFolder": "Impossibile eliminare la cartella",
|
||||||
"aboutApp": "Informazioni",
|
"aboutApp": "Informazioni",
|
||||||
"aboutAppSubtitle": "Informazioni e link di Conduit",
|
"aboutAppSubtitle": "Informazioni e link di iiEasy",
|
||||||
"web": "Web",
|
"web": "Web",
|
||||||
"imageGen": "Gen. immagini",
|
"imageGen": "Gen. immagini",
|
||||||
"pinned": "Fissati",
|
"pinned": "Fissati",
|
||||||
@@ -280,7 +281,7 @@
|
|||||||
"themeLight": "Chiaro",
|
"themeLight": "Chiaro",
|
||||||
"currentlyUsingDarkTheme": "Attualmente tema scuro",
|
"currentlyUsingDarkTheme": "Attualmente tema scuro",
|
||||||
"currentlyUsingLightTheme": "Attualmente tema chiaro",
|
"currentlyUsingLightTheme": "Attualmente tema chiaro",
|
||||||
"aboutConduit": "Informazioni su Conduit",
|
"aboutConduit": "Informazioni su iiEasy",
|
||||||
"versionLabel": "Versione: {version} ({build})",
|
"versionLabel": "Versione: {version} ({build})",
|
||||||
"@versionLabel": {
|
"@versionLabel": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -317,7 +318,7 @@
|
|||||||
"androidAssistantTitle": "Android digital assistant",
|
"androidAssistantTitle": "Android digital assistant",
|
||||||
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
"androidAssistantDescription": "Choose what happens when you trigger the Android digital assistant.",
|
||||||
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
"androidAssistantOverlayOption": "Show quick overlay (default)",
|
||||||
"androidAssistantNewChatOption": "Open Conduit with a new chat",
|
"androidAssistantNewChatOption": "Open iiEasy with a new chat",
|
||||||
"androidAssistantVoiceCallOption": "Start a voice call",
|
"androidAssistantVoiceCallOption": "Start a voice call",
|
||||||
"sttSettings": "Voce in testo",
|
"sttSettings": "Voce in testo",
|
||||||
"sttEngineLabel": "Motore di riconoscimento",
|
"sttEngineLabel": "Motore di riconoscimento",
|
||||||
@@ -650,11 +651,11 @@
|
|||||||
"@nextLabel": {
|
"@nextLabel": {
|
||||||
"description": "Label for navigating to the next item."
|
"description": "Label for navigating to the next item."
|
||||||
},
|
},
|
||||||
"themePaletteConduitLabel": "Conduit",
|
"themePaletteConduitLabel": "iiEasy",
|
||||||
"@themePaletteConduitLabel": {
|
"@themePaletteConduitLabel": {
|
||||||
"description": "Palette name for the default Conduit theme."
|
"description": "Palette name for the default Conduit theme."
|
||||||
},
|
},
|
||||||
"themePaletteConduitDescription": "Tema neutro e pulito progettato per Conduit.",
|
"themePaletteConduitDescription": "Tema neutro e pulito progettato per iiEasy.",
|
||||||
"@themePaletteConduitDescription": {
|
"@themePaletteConduitDescription": {
|
||||||
"description": "Description of the Conduit palette."
|
"description": "Description of the Conduit palette."
|
||||||
},
|
},
|
||||||
|
|||||||