Initialisation du projet geosector complet (web + flutter)
23
flutt/.cline
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"memoryBank": {
|
||||
"enabled": true,
|
||||
"path": "./docs",
|
||||
"maxContextSize": 100000
|
||||
},
|
||||
"contextSettings": {
|
||||
"maxTokens": 100000,
|
||||
"cline.maxAutoApprovedRequests": 100,
|
||||
"cline.enableMemoryBank": true,
|
||||
"cline.includeSnippetsFromMemory": true,
|
||||
"cline.contextLength": 10000,
|
||||
"cline.autoFormat": true
|
||||
},
|
||||
"mcpServers": {
|
||||
"github.com/modelcontextprotocol/servers/tree/main/src/git": {
|
||||
"command": "python",
|
||||
"args": ["-m", "mcp_server_git"],
|
||||
"disabled": false,
|
||||
"autoApprove": []
|
||||
}
|
||||
}
|
||||
}
|
||||
16
flutt/.env-backup
Normal file
@@ -0,0 +1,16 @@
|
||||
# Configuration pour le serveur de backup 1
|
||||
BACKUP_SERVER1_IP="192.168.1.7"
|
||||
BACKUP_SERVER1_PORT="22"
|
||||
BACKUP_SERVER1_USER="root"
|
||||
BACKUP_SERVER1_KEY="/Users/pierre/.ssh/id_rsa_mbpi"
|
||||
BACKUP_SERVER1_PATH="/var/backups"
|
||||
|
||||
# Configuration pour le serveur de backup 2
|
||||
BACKUP_SERVER2_IP="server2.example.com"
|
||||
BACKUP_SERVER2_PORT="22"
|
||||
BACKUP_SERVER2_USER="backup_user"
|
||||
BACKUP_SERVER2_KEY="/path/to/private_key2"
|
||||
BACKUP_SERVER2_PATH="/path/to/backups"
|
||||
|
||||
# Configuration générale
|
||||
BACKUP_RETENTION_DAYS=30 # Nombre de jours de conservation des backups
|
||||
15
flutt/.env-deploy-dev
Normal file
@@ -0,0 +1,15 @@
|
||||
# Paramètres de connexion au host Debian 12
|
||||
HOST_SSH_USER=debian
|
||||
HOST_SSH_HOST=145.239.9.105
|
||||
HOST_SSH_PORT=22
|
||||
HOST_SSH_KEY=/Users/pierre/.ssh/id_rsa_mbpi
|
||||
|
||||
# Paramètres du container Incus
|
||||
INCUS_PROJECT=DEV
|
||||
INCUS_CONTAINER=d-apps
|
||||
CONTAINER_USER=root
|
||||
USE_SUDO=true
|
||||
|
||||
# Paramètres de déploiement
|
||||
DEPLOY_TARGET_DIR=/var/www/geosector
|
||||
FLUTTER_BUILD_DIR=build/web
|
||||
47
flutt/.gitignore
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
sync_config.jsonc
|
||||
30
flutt/.metadata
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "c23637390482d4cf9598c3ce3f2be31aa7332daf"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
- platform: ios
|
||||
create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
0
flutt/.windsurfrules
Normal file
16
flutt/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# geosector_app
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
57
flutt/add_framework_paths.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'xcodeproj'
|
||||
|
||||
# Ouvrir le projet
|
||||
project_path = 'ios/Runner.xcodeproj'
|
||||
project = Xcodeproj::Project.open(project_path)
|
||||
|
||||
# Trouver la cible Runner
|
||||
target = project.targets.find { |t| t.name == 'Runner' }
|
||||
|
||||
# Parcourir toutes les configurations de build
|
||||
target.build_configurations.each do |config|
|
||||
# Obtenir les paramètres de build actuels
|
||||
build_settings = config.build_settings
|
||||
|
||||
# Définir les chemins de recherche de frameworks
|
||||
framework_search_paths = [
|
||||
'$(inherited)',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios"',
|
||||
'"${PODS_ROOT}/Flutter"',
|
||||
'"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter"'
|
||||
]
|
||||
|
||||
# Ajouter les chemins de recherche de frameworks
|
||||
build_settings['FRAMEWORK_SEARCH_PATHS'] = framework_search_paths
|
||||
|
||||
# Ajouter les chemins de recherche d'en-têtes
|
||||
header_search_paths = [
|
||||
'$(inherited)',
|
||||
'"${PODS_ROOT}/Flutter"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}"'
|
||||
]
|
||||
|
||||
build_settings['HEADER_SEARCH_PATHS'] = header_search_paths
|
||||
|
||||
# S'assurer que les modules sont activés
|
||||
build_settings['DEFINES_MODULE'] = 'YES'
|
||||
|
||||
# Désactiver le bitcode
|
||||
build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
|
||||
# Inclure tous les assets d'icônes
|
||||
build_settings['ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS'] = 'YES'
|
||||
|
||||
# Autres paramètres importants
|
||||
build_settings['SWIFT_VERSION'] = '5.0'
|
||||
build_settings['CLANG_ENABLE_MODULES'] = 'YES'
|
||||
end
|
||||
|
||||
# Enregistrer les modifications
|
||||
project.save
|
||||
|
||||
puts "✅ Chemins de recherche de frameworks ajoutés avec succès !"
|
||||
28
flutt/analysis_options.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
14
flutt/android/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
.cxx/
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/to/reference-keystore
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
44
flutt/android/app/build.gradle.kts
Normal file
@@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "fr.geosector.app.geosector_app"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "fr.geosector.app.geosector_app"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
7
flutt/android/app/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
48
flutt/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Permissions pour la géolocalisation -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<application
|
||||
android:label="geosector_app"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
package fr.geosector.app.geosector_app
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
BIN
flutt/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
flutt/android/app/src/main/res/mipmap-hdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
flutt/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
flutt/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
flutt/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
flutt/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
flutt/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
flutt/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
flutt/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
flutt/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
18
flutt/android/app/src/main/res/values-night/styles.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
18
flutt/android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
7
flutt/android/app/src/profile/AndroidManifest.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
21
flutt/android/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
|
||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
||||
|
||||
subprojects {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.layout.buildDirectory)
|
||||
}
|
||||
3
flutt/android/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
5
flutt/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
25
flutt/android/settings.gradle.kts
Normal file
@@ -0,0 +1,25 @@
|
||||
pluginManagement {
|
||||
val flutterSdkPath = run {
|
||||
val properties = java.util.Properties()
|
||||
file("local.properties").inputStream().use { properties.load(it) }
|
||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||
flutterSdkPath
|
||||
}
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.7.0" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
802
flutt/assets/animations/geo_main.json
Normal file
@@ -0,0 +1,802 @@
|
||||
{
|
||||
"v": "5.7.5",
|
||||
"fr": 30,
|
||||
"ip": 0,
|
||||
"op": 90,
|
||||
"w": 400,
|
||||
"h": 400,
|
||||
"nm": "GeoSector Animation",
|
||||
"ddd": 0,
|
||||
"assets": [],
|
||||
"layers": [
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 1,
|
||||
"ty": 4,
|
||||
"nm": "Earth",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 11
|
||||
},
|
||||
"r": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.833], "y": [0.833] },
|
||||
"o": { "x": [0.167], "y": [0.167] },
|
||||
"t": 0,
|
||||
"s": [0]
|
||||
},
|
||||
{
|
||||
"t": 90,
|
||||
"s": [360]
|
||||
}
|
||||
],
|
||||
"ix": 10
|
||||
},
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [200, 200, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] },
|
||||
"o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] },
|
||||
"t": 0,
|
||||
"s": [0, 0, 100]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] },
|
||||
"o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] },
|
||||
"t": 15,
|
||||
"s": [110, 110, 100]
|
||||
},
|
||||
{
|
||||
"t": 25,
|
||||
"s": [100, 100, 100]
|
||||
}
|
||||
],
|
||||
"ix": 6
|
||||
}
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"d": 1,
|
||||
"ty": "el",
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [120, 120],
|
||||
"ix": 2
|
||||
},
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 3
|
||||
},
|
||||
"nm": "Ellipse Path 1",
|
||||
"mn": "ADBE Vector Shape - Ellipse",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "st",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.125, 0.553, 0.965, 1],
|
||||
"ix": 3
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 4
|
||||
},
|
||||
"w": {
|
||||
"a": 0,
|
||||
"k": 4,
|
||||
"ix": 5
|
||||
},
|
||||
"lc": 1,
|
||||
"lj": 1,
|
||||
"ml": 4,
|
||||
"bm": 0,
|
||||
"nm": "Stroke 1",
|
||||
"mn": "ADBE Vector Graphic - Stroke",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.2, 0.6, 1, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 70,
|
||||
"ix": 5
|
||||
},
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Earth Base",
|
||||
"np": 3,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[-60, 0],
|
||||
[60, 0]
|
||||
],
|
||||
"c": false
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "st",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [1, 1, 1, 1],
|
||||
"ix": 3
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 30,
|
||||
"ix": 4
|
||||
},
|
||||
"w": {
|
||||
"a": 0,
|
||||
"k": 2,
|
||||
"ix": 5
|
||||
},
|
||||
"lc": 2,
|
||||
"lj": 1,
|
||||
"ml": 4,
|
||||
"bm": 0,
|
||||
"nm": "Stroke 1",
|
||||
"mn": "ADBE Vector Graphic - Stroke",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Equator",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 2,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[0, -60],
|
||||
[0, 60]
|
||||
],
|
||||
"c": false
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "st",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [1, 1, 1, 1],
|
||||
"ix": 3
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 30,
|
||||
"ix": 4
|
||||
},
|
||||
"w": {
|
||||
"a": 0,
|
||||
"k": 2,
|
||||
"ix": 5
|
||||
},
|
||||
"lc": 2,
|
||||
"lj": 1,
|
||||
"ml": 4,
|
||||
"bm": 0,
|
||||
"nm": "Stroke 1",
|
||||
"mn": "ADBE Vector Graphic - Stroke",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Meridian",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 3,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"d": 1,
|
||||
"ty": "el",
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [20, 20],
|
||||
"ix": 2
|
||||
},
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [40, -30],
|
||||
"ix": 3
|
||||
},
|
||||
"nm": "Ellipse Path 1",
|
||||
"mn": "ADBE Vector Shape - Ellipse",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.133, 0.624, 0.125, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 5
|
||||
},
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Continent 1",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 4,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"d": 1,
|
||||
"ty": "el",
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [25, 25],
|
||||
"ix": 2
|
||||
},
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [-35, 20],
|
||||
"ix": 3
|
||||
},
|
||||
"nm": "Ellipse Path 1",
|
||||
"mn": "ADBE Vector Shape - Ellipse",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.133, 0.624, 0.125, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 5
|
||||
},
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Continent 2",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 5,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 0,
|
||||
"op": 90,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
},
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 2,
|
||||
"ty": 4,
|
||||
"nm": "Marker Pin",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 11
|
||||
},
|
||||
"r": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.833], "y": [0.833] },
|
||||
"o": { "x": [0.167], "y": [0.167] },
|
||||
"t": 30,
|
||||
"s": [0]
|
||||
},
|
||||
{
|
||||
"t": 40,
|
||||
"s": [5]
|
||||
},
|
||||
{
|
||||
"t": 50,
|
||||
"s": [-5]
|
||||
},
|
||||
{
|
||||
"t": 60,
|
||||
"s": [0]
|
||||
}
|
||||
],
|
||||
"ix": 10
|
||||
},
|
||||
"p": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": 0.833, "y": 0.833 },
|
||||
"o": { "x": 0.167, "y": 0.167 },
|
||||
"t": 25,
|
||||
"s": [200, 80, 0],
|
||||
"to": [0, 0, 0],
|
||||
"ti": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"i": { "x": 0.833, "y": 0.833 },
|
||||
"o": { "x": 0.167, "y": 0.167 },
|
||||
"t": 30,
|
||||
"s": [200, 120, 0],
|
||||
"to": [0, 0, 0],
|
||||
"ti": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"t": 35,
|
||||
"s": [200, 110, 0]
|
||||
}
|
||||
],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] },
|
||||
"o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] },
|
||||
"t": 20,
|
||||
"s": [0, 0, 100]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] },
|
||||
"o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] },
|
||||
"t": 30,
|
||||
"s": [120, 120, 100]
|
||||
},
|
||||
{
|
||||
"t": 35,
|
||||
"s": [100, 100, 100]
|
||||
}
|
||||
],
|
||||
"ix": 6
|
||||
}
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[5.523, 0],
|
||||
[0, 5.523],
|
||||
[-5.523, 0],
|
||||
[0, -5.523],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 5.523],
|
||||
[-5.523, 0],
|
||||
[0, -5.523],
|
||||
[5.523, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[10, -5],
|
||||
[0, 5],
|
||||
[-10, -5],
|
||||
[0, -15],
|
||||
[10, -5],
|
||||
[0, 25]
|
||||
],
|
||||
"c": false
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "st",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.925, 0.267, 0.267, 1],
|
||||
"ix": 3
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 4
|
||||
},
|
||||
"w": {
|
||||
"a": 0,
|
||||
"k": 5,
|
||||
"ix": 5
|
||||
},
|
||||
"lc": 2,
|
||||
"lj": 2,
|
||||
"bm": 0,
|
||||
"nm": "Stroke 1",
|
||||
"mn": "ADBE Vector Graphic - Stroke",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.925, 0.267, 0.267, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 5
|
||||
},
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 2
|
||||
},
|
||||
"a": {
|
||||
"a": 0,
|
||||
"k": [0, 0],
|
||||
"ix": 1
|
||||
},
|
||||
"s": {
|
||||
"a": 0,
|
||||
"k": [100, 100],
|
||||
"ix": 3
|
||||
},
|
||||
"r": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 6
|
||||
},
|
||||
"o": {
|
||||
"a": 0,
|
||||
"k": 100,
|
||||
"ix": 7
|
||||
},
|
||||
"sk": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 4
|
||||
},
|
||||
"sa": {
|
||||
"a": 0,
|
||||
"k": 0,
|
||||
"ix": 5
|
||||
},
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Pin",
|
||||
"np": 3,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 20,
|
||||
"op": 90,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
}
|
||||
],
|
||||
"markers": []
|
||||
}
|
||||
43
flutt/assets/images/app-screenshot1.svg
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="300" height="600" viewBox="0 0 300 600" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fond de smartphone -->
|
||||
<rect width="300" height="600" rx="30" fill="#2E4057" />
|
||||
<rect x="10" y="30" width="280" height="540" rx="15" fill="#FFFFFF" />
|
||||
|
||||
<!-- Interface de l'application -->
|
||||
<rect x="10" y="30" width="280" height="60" rx="15" fill="#048BA8" />
|
||||
<circle cx="40" cy="60" r="15" fill="#FFFFFF" opacity="0.8" />
|
||||
<rect x="70" y="50" width="120" height="20" rx="5" fill="#FFFFFF" opacity="0.8" />
|
||||
<rect x="240" y="50" width="30" height="20" rx="5" fill="#FFFFFF" opacity="0.8" />
|
||||
|
||||
<!-- Carte -->
|
||||
<rect x="20" y="100" width="260" height="200" rx="5" fill="#E5E7EB" />
|
||||
<circle cx="150" cy="180" r="15" fill="#F18F01" stroke="#FFFFFF" stroke-width="3" />
|
||||
<circle cx="90" cy="150" r="8" fill="#048BA8" stroke="#FFFFFF" stroke-width="2" />
|
||||
<circle cx="210" cy="220" r="8" fill="#048BA8" stroke="#FFFFFF" stroke-width="2" />
|
||||
<rect x="120" y="130" width="60" height="40" rx="3" fill="#2E4057" opacity="0.6" />
|
||||
<rect x="70" y="200" width="40" height="30" rx="3" fill="#2E4057" opacity="0.6" />
|
||||
<rect x="180" y="160" width="50" height="30" rx="3" fill="#2E4057" opacity="0.6" />
|
||||
|
||||
<!-- Liste d'emplacements -->
|
||||
<rect x="20" y="310" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<circle cx="45" cy="340" r="15" fill="#F18F01" opacity="0.8" />
|
||||
<rect x="70" y="325" width="150" height="12" rx="2" fill="#2E4057" opacity="0.8" />
|
||||
<rect x="70" y="345" width="100" height="10" rx="2" fill="#9CA3AF" opacity="0.6" />
|
||||
|
||||
<rect x="20" y="380" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<circle cx="45" cy="410" r="15" fill="#048BA8" opacity="0.8" />
|
||||
<rect x="70" y="395" width="150" height="12" rx="2" fill="#2E4057" opacity="0.8" />
|
||||
<rect x="70" y="415" width="100" height="10" rx="2" fill="#9CA3AF" opacity="0.6" />
|
||||
|
||||
<rect x="20" y="450" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<circle cx="45" cy="480" r="15" fill="#2E4057" opacity="0.8" />
|
||||
<rect x="70" y="465" width="150" height="12" rx="2" fill="#2E4057" opacity="0.8" />
|
||||
<rect x="70" y="485" width="100" height="10" rx="2" fill="#9CA3AF" opacity="0.6" />
|
||||
|
||||
<!-- Navigation en bas -->
|
||||
<rect x="10" y="530" width="280" height="60" rx="15" fill="#F9FAFB" />
|
||||
<circle cx="60" cy="560" r="15" fill="#048BA8" />
|
||||
<circle cx="150" cy="560" r="15" fill="#9CA3AF" />
|
||||
<circle cx="240" cy="560" r="15" fill="#9CA3AF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
45
flutt/assets/images/app-screenshot2.svg
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="300" height="600" viewBox="0 0 300 600" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fond de smartphone -->
|
||||
<rect width="300" height="600" rx="30" fill="#2E4057" />
|
||||
<rect x="10" y="30" width="280" height="540" rx="15" fill="#FFFFFF" />
|
||||
|
||||
<!-- Interface de l'application - écran de détail -->
|
||||
<rect x="10" y="30" width="280" height="60" rx="15" fill="#048BA8" />
|
||||
<rect x="20" y="50" width="20" height="20" rx="5" fill="#FFFFFF" opacity="0.8" />
|
||||
<rect x="70" y="50" width="120" height="20" rx="5" fill="#FFFFFF" opacity="0.8" />
|
||||
<rect x="240" y="50" width="30" height="20" rx="5" fill="#FFFFFF" opacity="0.8" />
|
||||
|
||||
<!-- En-tête -->
|
||||
<rect x="20" y="100" width="260" height="120" rx="5" fill="#F9FAFB" />
|
||||
<circle cx="70" cy="140" r="30" fill="#F18F01" opacity="0.8" />
|
||||
<rect x="110" y="120" width="150" height="15" rx="2" fill="#2E4057" opacity="0.8" />
|
||||
<rect x="110" y="145" width="120" height="10" rx="2" fill="#9CA3AF" opacity="0.6" />
|
||||
<rect x="110" y="165" width="80" height="10" rx="2" fill="#9CA3AF" opacity="0.6" />
|
||||
|
||||
<!-- Données -->
|
||||
<rect x="20" y="240" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<rect x="30" y="255" width="80" height="15" rx="2" fill="#2E4057" opacity="0.6" />
|
||||
<rect x="30" y="275" width="240" height="15" rx="2" fill="#048BA8" opacity="0.8" />
|
||||
|
||||
<rect x="20" y="310" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<rect x="30" y="325" width="80" height="15" rx="2" fill="#2E4057" opacity="0.6" />
|
||||
<rect x="30" y="345" width="180" height="15" rx="2" fill="#048BA8" opacity="0.8" />
|
||||
|
||||
<rect x="20" y="380" width="260" height="60" rx="5" fill="#F9FAFB" stroke="#E5E7EB" stroke-width="1" />
|
||||
<rect x="30" y="395" width="80" height="15" rx="2" fill="#2E4057" opacity="0.6" />
|
||||
<rect x="30" y="415" width="210" height="15" rx="2" fill="#048BA8" opacity="0.8" />
|
||||
|
||||
<!-- Boutons -->
|
||||
<rect x="20" y="460" width="125" height="50" rx="25" fill="#F18F01" />
|
||||
<rect x="60" y="480" width="45" height="10" rx="2" fill="#FFFFFF" />
|
||||
|
||||
<rect x="155" y="460" width="125" height="50" rx="25" fill="#2E4057" />
|
||||
<rect x="195" y="480" width="45" height="10" rx="2" fill="#FFFFFF" />
|
||||
|
||||
<!-- Navigation en bas -->
|
||||
<rect x="10" y="530" width="280" height="60" rx="15" fill="#F9FAFB" />
|
||||
<circle cx="60" cy="560" r="15" fill="#9CA3AF" />
|
||||
<circle cx="150" cy="560" r="15" fill="#048BA8" />
|
||||
<circle cx="240" cy="560" r="15" fill="#9CA3AF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
13
flutt/assets/images/app-store-badge.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="160" height="50" viewBox="0 0 160 50" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fond du badge App Store -->
|
||||
<rect width="160" height="50" rx="8" fill="#000000" />
|
||||
|
||||
<!-- Logo Apple -->
|
||||
<path d="M39,16.5c1.7,0,3.4,1,4.6,2.8c-4,2.2-3.4,7.9,0.7,9.5c-0.6,1.7-1.3,3.4-2.7,5.1c-1.6,1.9-3.2,1.9-4.8,0.9c-1.6-0.9-3-0.9-4.6,0c-2.1,1.2-3.2,0.8-4.6-0.9c-2.8-3.2-3.8-9.1-1.6-13.1c1.6-2.9,4.2-3.3,6.4-1.9c1.2,0.8,2.3,0.8,3.6,0C37.3,17.5,38.2,16.5,39,16.5z" fill="#FFFFFF" />
|
||||
<path d="M42.8,13.2c0,1.7-1.5,3.1-3.3,3.2c-0.1-2.5,2.2-3.7,3.3-3.9C42.8,12.5,42.8,12.8,42.8,13.2z" fill="#FFFFFF" />
|
||||
|
||||
<!-- Texte App Store -->
|
||||
<text x="60" y="25" font-family="Arial" font-size="14" font-weight="600" fill="#FFFFFF">Download on the</text>
|
||||
<text x="60" y="43" font-family="Arial" font-size="20" font-weight="800" fill="#FFFFFF">App Store</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 897 B |
69
flutt/assets/images/city-map-bg-fixed.svg
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="800" height="600" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fond de carte léger -->
|
||||
<rect width="800" height="600" fill="#F9FAFB" />
|
||||
|
||||
<!-- Grille principale de rues -->
|
||||
<g stroke="#E5E7EB" stroke-width="2">
|
||||
<!-- Rues horizontales -->
|
||||
<line x1="0" y1="100" x2="800" y2="100" />
|
||||
<line x1="0" y1="200" x2="800" y2="200" />
|
||||
<line x1="0" y1="300" x2="800" y2="300" />
|
||||
<line x1="0" y1="400" x2="800" y2="400" />
|
||||
<line x1="0" y1="500" x2="800" y2="500" />
|
||||
|
||||
<!-- Rues verticales -->
|
||||
<line x1="100" y1="0" x2="100" y2="600" />
|
||||
<line x1="200" y1="0" x2="200" y2="600" />
|
||||
<line x1="300" y1="0" x2="300" y2="600" />
|
||||
<line x1="400" y1="0" x2="400" y2="600" />
|
||||
<line x1="500" y1="0" x2="500" y2="600" />
|
||||
<line x1="600" y1="0" x2="600" y2="600" />
|
||||
<line x1="700" y1="0" x2="700" y2="600" />
|
||||
</g>
|
||||
|
||||
<!-- Rues secondaires -->
|
||||
<g stroke="#E5E7EB" stroke-width="1">
|
||||
<line x1="50" y1="0" x2="50" y2="600" />
|
||||
<line x1="150" y1="0" x2="150" y2="600" />
|
||||
<line x1="250" y1="0" x2="250" y2="600" />
|
||||
<line x1="350" y1="0" x2="350" y2="600" />
|
||||
<line x1="450" y1="0" x2="450" y2="600" />
|
||||
<line x1="550" y1="0" x2="550" y2="600" />
|
||||
<line x1="650" y1="0" x2="650" y2="600" />
|
||||
<line x1="750" y1="0" x2="750" y2="600" />
|
||||
|
||||
<line x1="0" y1="50" x2="800" y2="50" />
|
||||
<line x1="0" y1="150" x2="800" y2="150" />
|
||||
<line x1="0" y1="250" x2="800" y2="250" />
|
||||
<line x1="0" y1="350" x2="800" y2="350" />
|
||||
<line x1="0" y1="450" x2="800" y2="450" />
|
||||
<line x1="0" y1="550" x2="800" y2="550" />
|
||||
</g>
|
||||
|
||||
<!-- Points d'intérêt (POI) -->
|
||||
<g fill="#D1D5DB">
|
||||
<rect x="120" y="120" width="60" height="60" rx="5" />
|
||||
<rect x="320" y="220" width="40" height="40" rx="5" />
|
||||
<rect x="520" y="320" width="50" height="70" rx="5" />
|
||||
<rect x="220" y="420" width="70" height="50" rx="5" />
|
||||
<rect x="620" y="120" width="50" height="50" rx="5" />
|
||||
<rect x="420" y="470" width="40" height="60" rx="5" />
|
||||
</g>
|
||||
|
||||
<!-- Parcs et espaces verts -->
|
||||
<g fill="#E0F2F1" opacity="0.6">
|
||||
<circle cx="150" cy="350" r="40" />
|
||||
<circle cx="550" cy="150" r="30" />
|
||||
<circle cx="650" cy="450" r="50" />
|
||||
<circle cx="350" cy="550" r="35" />
|
||||
<rect x="250" y="180" width="80" height="60" rx="10" />
|
||||
</g>
|
||||
|
||||
<!-- Routes principales -->
|
||||
<g stroke="#9CA3AF" stroke-width="5" opacity="0.4">
|
||||
<line x1="0" y1="300" x2="800" y2="300" />
|
||||
<line x1="400" y1="0" x2="400" y2="600" />
|
||||
<path d="M800,100 C600,200 300,300 0,500" fill="none" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
133
flutt/assets/images/city-map-bg.svg
Normal file
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1000" height="1000" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Paramètres de base -->
|
||||
<defs>
|
||||
<!-- Style pour les rues principales -->
|
||||
<style type="text/css">
|
||||
.street-main {
|
||||
stroke: rgba(46, 64, 87, 0.08);
|
||||
stroke-width: 4;
|
||||
fill: none;
|
||||
}
|
||||
.street-secondary {
|
||||
stroke: rgba(46, 64, 87, 0.05);
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
.street-tertiary {
|
||||
stroke: rgba(46, 64, 87, 0.03);
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
.block {
|
||||
fill: rgba(4, 139, 168, 0.02);
|
||||
stroke: rgba(4, 139, 168, 0.04);
|
||||
stroke-width: 0.5;
|
||||
}
|
||||
.landmark {
|
||||
fill: rgba(241, 143, 1, 0.03);
|
||||
stroke: rgba(241, 143, 1, 0.06);
|
||||
stroke-width: 0.5;
|
||||
}
|
||||
.water {
|
||||
fill: rgba(4, 139, 168, 0.04);
|
||||
stroke: none;
|
||||
}
|
||||
.park {
|
||||
fill: rgba(4, 139, 168, 0.02);
|
||||
stroke: rgba(4, 139, 168, 0.04);
|
||||
stroke-width: 0.5;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<!-- Fond transparent -->
|
||||
<rect width="100%" height="100%" fill="none" />
|
||||
|
||||
<!-- Rivière/Étendue d'eau -->
|
||||
<path class="water" d="M0,400 C100,380 200,450 300,430 C400,410 500,390 600,400 C700,410 800,440 900,430 C950,425 1000,420 1000,420 L1000,550 C950,545 900,540 850,535 C750,525 650,520 550,530 C450,540 350,560 250,550 C150,540 50,520 0,510 Z" />
|
||||
|
||||
<!-- Grille de rues principales -->
|
||||
<line class="street-main" x1="100" y1="0" x2="100" y2="1000" />
|
||||
<line class="street-main" x1="300" y1="0" x2="300" y2="1000" />
|
||||
<line class="street-main" x1="500" y1="0" x2="500" y2="1000" />
|
||||
<line class="street-main" x1="700" y1="0" x2="700" y2="1000" />
|
||||
<line class="street-main" x1="900" y1="0" x2="900" y2="1000" />
|
||||
|
||||
<line class="street-main" x1="0" y1="100" x2="1000" y2="100" />
|
||||
<line class="street-main" x1="0" y1="300" x2="1000" y2="300" />
|
||||
<line class="street-main" x1="0" y1="600" x2="1000" y2="600" />
|
||||
<line class="street-main" x1="0" y1="800" x2="1000" y2="800" />
|
||||
|
||||
<!-- Rues secondaires -->
|
||||
<line class="street-secondary" x1="50" y1="0" x2="50" y2="1000" />
|
||||
<line class="street-secondary" x1="200" y1="0" x2="200" y2="1000" />
|
||||
<line class="street-secondary" x1="400" y1="0" x2="400" y2="1000" />
|
||||
<line class="street-secondary" x1="600" y1="0" x2="600" y2="1000" />
|
||||
<line class="street-secondary" x1="800" y1="0" x2="800" y2="1000" />
|
||||
|
||||
<line class="street-secondary" x1="0" y1="50" x2="1000" y2="50" />
|
||||
<line class="street-secondary" x1="0" y1="200" x2="1000" y2="200" />
|
||||
<line class="street-secondary" x1="0" y1="400" x2="1000" y2="400" />
|
||||
<line class="street-secondary" x1="0" y1="500" x2="1000" y2="500" />
|
||||
<line class="street-secondary" x1="0" y1="700" x2="1000" y2="700" />
|
||||
<line class="street-secondary" x1="0" y1="900" x2="1000" y2="900" />
|
||||
|
||||
<!-- Rues tertiaires et ruelles -->
|
||||
<line class="street-tertiary" x1="25" y1="0" x2="25" y2="1000" />
|
||||
<line class="street-tertiary" x1="75" y1="0" x2="75" y2="1000" />
|
||||
<line class="street-tertiary" x1="125" y1="0" x2="125" y2="1000" />
|
||||
<line class="street-tertiary" x1="175" y1="0" x2="175" y2="1000" />
|
||||
<line class="street-tertiary" x1="225" y1="0" x2="225" y2="1000" />
|
||||
<line class="street-tertiary" x1="250" y1="0" x2="250" y2="1000" />
|
||||
<line class="street-tertiary" x1="350" y1="0" x2="350" y2="1000" />
|
||||
<line class="street-tertiary" x1="450" y1="0" x2="450" y2="1000" />
|
||||
<line class="street-tertiary" x1="550" y1="0" x2="550" y2="1000" />
|
||||
<line class="street-tertiary" x1="650" y1="0" x2="650" y2="1000" />
|
||||
<line class="street-tertiary" x1="750" y1="0" x2="750" y2="1000" />
|
||||
<line class="street-tertiary" x1="850" y1="0" x2="850" y2="1000" />
|
||||
<line class="street-tertiary" x1="950" y1="0" x2="950" y2="1000" />
|
||||
|
||||
<line class="street-tertiary" x1="0" y1="25" x2="1000" y2="25" />
|
||||
<line class="street-tertiary" x1="0" y1="75" x2="1000" y2="75" />
|
||||
<line class="street-tertiary" x1="0" y1="125" x2="1000" y2="125" />
|
||||
<line class="street-tertiary" x1="0" y1="175" x2="1000" y2="175" />
|
||||
<line class="street-tertiary" x1="0" y1="225" x2="1000" y2="225" />
|
||||
<line class="street-tertiary" x1="0" y1="250" x2="1000" y2="250" />
|
||||
<line class="street-tertiary" x1="0" y1="350" x2="1000" y2="350" />
|
||||
<line class="street-tertiary" x1="0" y1="450" x2="1000" y2="450" />
|
||||
<line class="street-tertiary" x1="0" y1="550" x2="1000" y2="550" />
|
||||
<line class="street-tertiary" x1="0" y1="650" x2="1000" y2="650" />
|
||||
<line class="street-tertiary" x1="0" y1="750" x2="1000" y2="750" />
|
||||
<line class="street-tertiary" x1="0" y1="850" x2="1000" y2="850" />
|
||||
<line class="street-tertiary" x1="0" y1="950" x2="1000" y2="950" />
|
||||
|
||||
<!-- Blocs et bâtiments -->
|
||||
<rect class="block" x="110" y="110" width="80" height="80" />
|
||||
<rect class="block" x="310" y="110" width="80" height="80" />
|
||||
<rect class="block" x="510" y="110" width="80" height="80" />
|
||||
<rect class="block" x="710" y="110" width="80" height="80" />
|
||||
<rect class="block" x="110" y="310" width="80" height="80" />
|
||||
<rect class="block" x="310" y="310" width="80" height="80" />
|
||||
<rect class="block" x="510" y="310" width="80" height="80" />
|
||||
<rect class="block" x="710" y="310" width="80" height="80" />
|
||||
<rect class="block" x="110" y="610" width="80" height="80" />
|
||||
<rect class="block" x="310" y="610" width="80" height="80" />
|
||||
<rect class="block" x="510" y="610" width="80" height="80" />
|
||||
<rect class="block" x="710" y="610" width="80" height="80" />
|
||||
<rect class="block" x="110" y="810" width="80" height="80" />
|
||||
<rect class="block" x="310" y="810" width="80" height="80" />
|
||||
<rect class="block" x="510" y="810" width="80" height="80" />
|
||||
<rect class="block" x="710" y="810" width="80" height="80" />
|
||||
|
||||
<!-- Points d'intérêt -->
|
||||
<circle class="landmark" cx="500" cy="200" r="30" />
|
||||
<rect class="landmark" x="400" y="700" width="200" height="70" rx="10" ry="10" />
|
||||
<polygon class="landmark" points="800,150 850,200 800,250 750,200" />
|
||||
|
||||
<!-- Parcs et espaces verts -->
|
||||
<rect class="park" x="150" y="150" width="100" height="100" rx="20" ry="20" />
|
||||
<rect class="park" x="650" y="450" width="100" height="100" rx="20" ry="20" />
|
||||
<circle class="park" cx="250" cy="750" r="50" />
|
||||
<ellipse class="park" cx="750" cy="650" rx="70" ry="40" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
BIN
flutt/assets/images/geosector-logo-200.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
flutt/assets/images/geosector-logo-200.png~
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
flutt/assets/images/geosector-logo-80.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
flutt/assets/images/geosector-logo-80.png~
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
flutt/assets/images/geosector-logo.png
Normal file
|
After Width: | Height: | Size: 342 KiB |
BIN
flutt/assets/images/geosector-logo.png~
Normal file
|
After Width: | Height: | Size: 342 KiB |
15
flutt/assets/images/play-store-badge.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="180" height="50" viewBox="0 0 180 50" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Fond du badge Google Play -->
|
||||
<rect width="180" height="50" rx="8" fill="#000000" />
|
||||
|
||||
<!-- Logo Google Play -->
|
||||
<path d="M30,10l-15,15l15,15l3-3l-12-12l12-12L30,10z" fill="#EA4335" />
|
||||
<path d="M30,10v30l12-15L30,10z" fill="#FBBC05" />
|
||||
<path d="M30,10l-15,15l3,3l12-12V10z" fill="#4285F4" />
|
||||
<path d="M30,40l-15-15l3-3l12,12V40z" fill="#34A853" />
|
||||
|
||||
<!-- Texte Google Play -->
|
||||
<text x="60" y="25" font-family="Arial" font-size="14" font-weight="600" fill="#FFFFFF">GET IT ON</text>
|
||||
<text x="60" y="43" font-family="Arial" font-size="20" font-weight="800" fill="#FFFFFF">Google Play</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 748 B |
81
flutt/backup.sh
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Chemin du projet
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_NAME="$(basename "$PROJECT_DIR")"
|
||||
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
||||
BACKUP_FILENAME="${PROJECT_NAME}_${TIMESTAMP}.tar.gz"
|
||||
TEMP_BACKUP_DIR="/tmp"
|
||||
BACKUP_PATH="${TEMP_BACKUP_DIR}/${BACKUP_FILENAME}"
|
||||
|
||||
# Charger les variables d'environnement
|
||||
if [ ! -f "${PROJECT_DIR}/.env-backup" ]; then
|
||||
echo "❌ Fichier .env-backup manquant"
|
||||
exit 1
|
||||
fi
|
||||
source "${PROJECT_DIR}/.env-backup"
|
||||
|
||||
# Fonction pour gérer les erreurs
|
||||
error_exit() {
|
||||
echo "❌ $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Fonction pour nettoyer les anciens backups
|
||||
cleanup_old_backups() {
|
||||
local server_ip=$1
|
||||
local server_port=$2
|
||||
local server_user=$3
|
||||
local server_key=$4
|
||||
local server_path=$5
|
||||
|
||||
echo "🧹 Nettoyage des backups plus anciens que ${BACKUP_RETENTION_DAYS} jours sur $server_ip..."
|
||||
ssh -i "$server_key" -p "$server_port" "$server_user@$server_ip" \
|
||||
"find $server_path -name '${PROJECT_NAME}_*.tar.gz' -type f -mtime +${BACKUP_RETENTION_DAYS} -delete" || \
|
||||
echo "⚠️ Avertissement: Nettoyage des anciens backups sur $server_ip échoué"
|
||||
}
|
||||
|
||||
# Création du backup
|
||||
echo "📦 Création du backup de ${PROJECT_NAME}..."
|
||||
cd "${PROJECT_DIR}/.."
|
||||
tar -czf "$BACKUP_PATH" \
|
||||
--exclude="${PROJECT_NAME}/build" \
|
||||
--exclude="${PROJECT_NAME}/.dart_tool" \
|
||||
--exclude="${PROJECT_NAME}/.pub" \
|
||||
--exclude="${PROJECT_NAME}/.flutter-plugins-dependencies" \
|
||||
--exclude="${PROJECT_NAME}/ios/Pods" \
|
||||
--exclude="${PROJECT_NAME}/android/.gradle" \
|
||||
--exclude="${PROJECT_NAME}/.git" \
|
||||
--exclude="${PROJECT_NAME}/node_modules" \
|
||||
"${PROJECT_NAME}/" || error_exit "Création du backup échouée"
|
||||
|
||||
echo "✅ Backup créé: $BACKUP_PATH ($(du -h "$BACKUP_PATH" | cut -f1))"
|
||||
|
||||
# Transfert vers le serveur 1
|
||||
echo "📤 Envoi du backup vers ${BACKUP_SERVER1_IP}..."
|
||||
scp -i "$BACKUP_SERVER1_KEY" -P "$BACKUP_SERVER1_PORT" "$BACKUP_PATH" \
|
||||
"${BACKUP_SERVER1_USER}@${BACKUP_SERVER1_IP}:${BACKUP_SERVER1_PATH}/" || \
|
||||
error_exit "Transfert vers ${BACKUP_SERVER1_IP} échoué"
|
||||
|
||||
echo "✅ Backup envoyé vers ${BACKUP_SERVER1_IP}"
|
||||
cleanup_old_backups "$BACKUP_SERVER1_IP" "$BACKUP_SERVER1_PORT" "$BACKUP_SERVER1_USER" \
|
||||
"$BACKUP_SERVER1_KEY" "$BACKUP_SERVER1_PATH"
|
||||
|
||||
# Transfert vers le serveur 2
|
||||
echo "📤 Envoi du backup vers ${BACKUP_SERVER2_IP}..."
|
||||
scp -i "$BACKUP_SERVER2_KEY" -P "$BACKUP_SERVER2_PORT" "$BACKUP_PATH" \
|
||||
"${BACKUP_SERVER2_USER}@${BACKUP_SERVER2_IP}:${BACKUP_SERVER2_PATH}/" || \
|
||||
error_exit "Transfert vers ${BACKUP_SERVER2_IP} échoué"
|
||||
|
||||
echo "✅ Backup envoyé vers ${BACKUP_SERVER2_IP}"
|
||||
cleanup_old_backups "$BACKUP_SERVER2_IP" "$BACKUP_SERVER2_PORT" "$BACKUP_SERVER2_USER" \
|
||||
"$BACKUP_SERVER2_KEY" "$BACKUP_SERVER2_PATH"
|
||||
|
||||
# Nettoyage du fichier temporaire
|
||||
echo "🧹 Suppression du fichier temporaire..."
|
||||
rm "$BACKUP_PATH" || echo "⚠️ Avertissement: Suppression du fichier temporaire échouée"
|
||||
|
||||
echo "✅ Backup terminé avec succès à $(date '+%H:%M:%S') !"
|
||||
echo "📂 Fichiers sauvegardés sur:"
|
||||
echo " - ${BACKUP_SERVER1_IP}:${BACKUP_SERVER1_PATH}/${BACKUP_FILENAME}"
|
||||
echo " - ${BACKUP_SERVER2_IP}:${BACKUP_SERVER2_PATH}/${BACKUP_FILENAME}"
|
||||
39
flutt/clean_flutter.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Afficher les commandes en cours d'exécution
|
||||
set -x
|
||||
|
||||
# Vérifier si nous sommes dans un projet Flutter
|
||||
if [ ! -f "pubspec.yaml" ]; then
|
||||
echo "Erreur: Assurez-vous d'être dans un projet Flutter (pubspec.yaml non trouvé)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Nettoyer Flutter et générer le code
|
||||
flutter pub run build_runner clean
|
||||
flutter pub run build_runner build --delete-conflicting-outputs
|
||||
flutter clean
|
||||
|
||||
# Nettoyer iOS
|
||||
cd ios || exit
|
||||
rm -rf Pods/
|
||||
rm -rf .symlinks/
|
||||
rm -f Podfile.lock
|
||||
pod cache clean --all
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData
|
||||
|
||||
# Retour au dossier racine et mise à jour des dépendances
|
||||
cd ..
|
||||
flutter pub get
|
||||
|
||||
# Réinstaller les pods iOS
|
||||
cd ios || exit
|
||||
pod deintegrate
|
||||
pod cache clean --all
|
||||
pod repo update
|
||||
pod install
|
||||
|
||||
# Retour au dossier racine
|
||||
cd ..
|
||||
|
||||
echo "Nettoyage terminé avec succès!"
|
||||
58
flutt/deploy-dev.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
cd /Users/pierre/dev/geosector/flutt
|
||||
|
||||
# Charger les variables d'environnement
|
||||
if [ ! -f .env-deploy-dev ]; then
|
||||
echo "❌ Fichier .env-deploy-dev manquant"
|
||||
exit 1
|
||||
fi
|
||||
source .env-deploy-dev
|
||||
|
||||
# Fonction pour gérer les erreurs
|
||||
error_exit() {
|
||||
echo "❌ $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Construction de l'application Flutter
|
||||
echo "🧹 Cleaning previous builds..."
|
||||
flutter clean || error_exit "Flutter clean failed"
|
||||
|
||||
echo "📦 Getting dependencies..."
|
||||
flutter pub get || error_exit "Flutter pub get failed"
|
||||
|
||||
# Nettoyage et génération du code
|
||||
echo "🗑️ Cleaning generated files..."
|
||||
dart pub run build_runner clean || error_exit "Build runner clean failed"
|
||||
|
||||
echo "🔨 Generating code files..."
|
||||
dart pub run build_runner build --delete-conflicting-outputs || error_exit "Code generation failed"
|
||||
|
||||
# Construction de l'application Flutter
|
||||
echo "🏗️ Building Flutter web application..."
|
||||
flutter build web --release || error_exit "Flutter build failed"
|
||||
|
||||
echo "✅ Build completed successfully!"
|
||||
|
||||
# Préparation de la commande SSH pour le host
|
||||
SSH_HOST_CMD="ssh -i $HOST_SSH_KEY -p $HOST_SSH_PORT $HOST_SSH_USER@$HOST_SSH_HOST"
|
||||
|
||||
# Préparation du chemin temporaire sur le host
|
||||
TEMP_DIR="/tmp/geosector-deploy-$(date +%s)"
|
||||
|
||||
echo "📤 Copie des fichiers vers le host temporairement..."
|
||||
rsync -rltz --delete \
|
||||
-e "ssh -i $HOST_SSH_KEY -p $HOST_SSH_PORT" \
|
||||
$FLUTTER_BUILD_DIR/ \
|
||||
$HOST_SSH_USER@$HOST_SSH_HOST:$TEMP_DIR/ || error_exit "Transfert vers le host échoué"
|
||||
|
||||
echo "🔄 Transfert des fichiers du host vers le container..."
|
||||
$SSH_HOST_CMD "sudo incus project switch $INCUS_PROJECT && sudo incus file push -r $TEMP_DIR/* $INCUS_CONTAINER$DEPLOY_TARGET_DIR/" || error_exit "Transfert vers le container échoué"
|
||||
|
||||
echo "🧹 Nettoyage du répertoire temporaire sur le host..."
|
||||
$SSH_HOST_CMD "rm -rf $TEMP_DIR"
|
||||
|
||||
echo "🔒 Configuration des permissions dans le container..."
|
||||
$SSH_HOST_CMD "sudo incus project switch $INCUS_PROJECT && sudo incus exec $INCUS_CONTAINER -- chown -R www-data:www-data $DEPLOY_TARGET_DIR" || error_exit "Configuration des permissions échouée"
|
||||
|
||||
echo "✅ Déploiement terminé avec succès à $(date '+%H:%M:%S') !"
|
||||
622
flutt/docs/chat.md
Normal file
@@ -0,0 +1,622 @@
|
||||
# Solution de Chat pour Applications Flutter
|
||||
|
||||
## Présentation générale
|
||||
|
||||
Cette solution propose un système de chat personnalisé et autonome pour des applications Flutter, avec possibilité d'intégration web. Elle est conçue pour fonctionner dans deux contextes différents :
|
||||
|
||||
1. **Chat entre utilisateurs authentifiés** (cas Geosector) : communications one-to-one ou en groupe entre utilisateurs déjà enregistrés dans la base de données.
|
||||
2. **Chat entre professionnels et visiteurs anonymes** (cas Resalice) : communications initiées par des visiteurs anonymes qui peuvent ensuite être convertis en clients référencés.
|
||||
|
||||
## Architecture technique
|
||||
|
||||
### 1. Structure générale
|
||||
|
||||
La solution s'articule autour de trois composants principaux :
|
||||
|
||||
- **Module Flutter** : Widgets et logique pour l'interface utilisateur mobile
|
||||
- **Module Web** : Composants pour l'intégration web (compatible avec Flutter Web ou sites traditionnels)
|
||||
- **API Backend** : Endpoints REST pour la gestion des messages et la synchronisation
|
||||
|
||||
### 2. Modèle de données
|
||||
|
||||
#### Entités principales
|
||||
|
||||
```
|
||||
Conversation
|
||||
├── id : Identifiant unique
|
||||
├── type : Type de conversation (one_to_one, group, anonymous, broadcast, announcement)
|
||||
├── title : Titre facultatif pour les groupes et obligatoire pour les annonces
|
||||
├── reply_permission : Niveau de permission pour répondre (all, admins_only, sender_only, none)
|
||||
├── created_at : Date de création
|
||||
├── updated_at : Dernière mise à jour
|
||||
├── is_pinned : Indique si la conversation est épinglée (pour annonces importantes)
|
||||
├── expiry_date : Date d'expiration optionnelle (pour annonces temporaires)
|
||||
└── participants : Liste des participants
|
||||
|
||||
Message
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── sender_id : ID de l'expéditeur (null pour anonyme)
|
||||
├── sender_type : Type d'expéditeur (user, anonymous, system)
|
||||
├── content : Contenu du message
|
||||
├── content_type : Type de contenu (text, image, file)
|
||||
├── created_at : Date d'envoi
|
||||
├── delivered_at : Date de réception
|
||||
├── read_at : Date de lecture
|
||||
├── status : Statut du message (sent, delivered, read, error)
|
||||
└── is_announcement : Indique s'il s'agit d'une annonce officielle
|
||||
|
||||
Participant
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── user_id : ID de l'utilisateur (si authentifié)
|
||||
├── anonymous_id : ID anonyme (pour Resalice)
|
||||
├── role : Rôle (admin, member, read_only)
|
||||
├── joined_at : Date d'ajout à la conversation
|
||||
├── via_target : Indique si l'utilisateur est inclus via un AudienceTarget
|
||||
├── can_reply : Possibilité explicite de répondre (override de reply_permission)
|
||||
└── last_read_message_id : ID du dernier message lu
|
||||
|
||||
AudienceTarget
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── target_type : Type de cible (role, entity, all, combined)
|
||||
├── target_id : ID du rôle ou de l'entité ciblée (pour compatibility)
|
||||
├── role_filter : Filtre de rôle pour le ciblage combiné ('all', '1', '2', etc.)
|
||||
├── entity_filter : Filtre d'entité pour le ciblage combiné ('all', 'id_entité')
|
||||
└── created_at : Date de création
|
||||
|
||||
AnonymousUser (pour Resalice)
|
||||
├── id : Identifiant unique
|
||||
├── device_id : Identifiant du dispositif
|
||||
├── name : Nom temporaire (si fourni)
|
||||
├── email : Email (si fourni)
|
||||
├── created_at : Date de création
|
||||
├── converted_to_user_id : ID utilisateur après conversion
|
||||
└── metadata : Informations supplémentaires
|
||||
```
|
||||
|
||||
#### Adaptations pour Hive
|
||||
|
||||
Ces modèles seront adaptés pour Hive avec leurs adaptateurs respectifs :
|
||||
|
||||
```dart
|
||||
@HiveType(typeId: 20)
|
||||
class ConversationModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String id;
|
||||
|
||||
@HiveField(1)
|
||||
final String type;
|
||||
|
||||
@HiveField(2)
|
||||
final String? title;
|
||||
|
||||
@HiveField(3)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(4)
|
||||
final DateTime updatedAt;
|
||||
|
||||
@HiveField(5)
|
||||
final List<ParticipantModel> participants;
|
||||
|
||||
@HiveField(6)
|
||||
final bool isSynced;
|
||||
|
||||
@HiveField(7)
|
||||
final String replyPermission;
|
||||
|
||||
@HiveField(8)
|
||||
final bool isPinned;
|
||||
|
||||
@HiveField(9)
|
||||
final DateTime? expiryDate;
|
||||
|
||||
// ... autres propriétés et méthodes
|
||||
}
|
||||
|
||||
@HiveType(typeId: 21)
|
||||
class MessageModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String id;
|
||||
|
||||
@HiveField(1)
|
||||
final String conversationId;
|
||||
|
||||
@HiveField(2)
|
||||
final String? senderId;
|
||||
|
||||
@HiveField(3)
|
||||
final String senderType;
|
||||
|
||||
@HiveField(4)
|
||||
final String content;
|
||||
|
||||
@HiveField(5)
|
||||
final String contentType;
|
||||
|
||||
@HiveField(6)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(7)
|
||||
final DateTime? deliveredAt;
|
||||
|
||||
@HiveField(8)
|
||||
final DateTime? readAt;
|
||||
|
||||
@HiveField(9)
|
||||
final String status;
|
||||
|
||||
@HiveField(10)
|
||||
final bool isAnnouncement;
|
||||
|
||||
// ... autres propriétés et méthodes
|
||||
}
|
||||
|
||||
@HiveType(typeId: 22)
|
||||
class ParticipantModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String id;
|
||||
|
||||
@HiveField(1)
|
||||
final String conversationId;
|
||||
|
||||
@HiveField(2)
|
||||
final String? userId;
|
||||
|
||||
@HiveField(3)
|
||||
final String? anonymousId;
|
||||
|
||||
@HiveField(4)
|
||||
final String role;
|
||||
|
||||
@HiveField(5)
|
||||
final DateTime joinedAt;
|
||||
|
||||
@HiveField(6)
|
||||
final String? lastReadMessageId;
|
||||
|
||||
@HiveField(7)
|
||||
final bool viaTarget;
|
||||
|
||||
@HiveField(8)
|
||||
final bool? canReply;
|
||||
|
||||
// ... autres propriétés et méthodes
|
||||
}
|
||||
|
||||
@HiveType(typeId: 23)
|
||||
class AudienceTargetModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String id;
|
||||
|
||||
@HiveField(1)
|
||||
final String conversationId;
|
||||
|
||||
@HiveField(2)
|
||||
final String targetType;
|
||||
|
||||
@HiveField(3)
|
||||
final String? targetId;
|
||||
|
||||
@HiveField(4)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(5)
|
||||
final String? roleFilter; // 'all' ou ID de rôle
|
||||
|
||||
@HiveField(6)
|
||||
final String? entityFilter; // 'all' ou ID d'entité
|
||||
|
||||
// ... autres propriétés et méthodes
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Backend et API
|
||||
|
||||
#### Structure de l'API
|
||||
|
||||
L'API sera développée en PHP 8.3 pour s'intégrer avec vos systèmes existants :
|
||||
|
||||
```
|
||||
/api/chat/conversations
|
||||
GET - Liste des conversations de l'utilisateur
|
||||
POST - Créer une nouvelle conversation
|
||||
|
||||
/api/chat/conversations/{id}
|
||||
GET - Détails d'une conversation
|
||||
PUT - Mettre à jour une conversation
|
||||
DELETE - Supprimer une conversation
|
||||
|
||||
/api/chat/conversations/{id}/messages
|
||||
GET - Messages d'une conversation (pagination)
|
||||
POST - Envoyer un message
|
||||
|
||||
/api/chat/conversations/{id}/participants
|
||||
GET - Liste des participants
|
||||
POST - Ajouter un participant
|
||||
DELETE - Retirer un participant
|
||||
|
||||
/api/chat/messages/{id}
|
||||
PUT - Mettre à jour un message (ex: marquer comme lu)
|
||||
DELETE - Supprimer un message
|
||||
|
||||
/api/chat/anonymous
|
||||
POST - Démarrer une conversation anonyme
|
||||
|
||||
# Nouveaux endpoints pour les annonces
|
||||
/api/chat/announcements
|
||||
GET - Liste des annonces pour l'utilisateur
|
||||
POST - Créer une nouvelle annonce
|
||||
|
||||
/api/chat/announcements/{id}/stats
|
||||
GET - Obtenir les statistiques de lecture (qui a lu/non lu)
|
||||
|
||||
/api/chat/audience-targets
|
||||
GET - Obtenir les cibles disponibles pour l'utilisateur actuel
|
||||
|
||||
/api/chat/conversations/{id}/pin
|
||||
PUT - Épingler/désépingler une conversation
|
||||
|
||||
/api/chat/conversations/{id}/reply-permission
|
||||
PUT - Modifier les permissions de réponse
|
||||
```
|
||||
|
||||
#### Synchronisation
|
||||
|
||||
Le système supportera :
|
||||
|
||||
- Synchronisation en temps réel via WebSockets (optionnel)
|
||||
- Synchronisation par polling avec gestion des messages non lus
|
||||
- Enregistrement local des messages avec Hive pour le fonctionnement hors ligne
|
||||
|
||||
### 4. Widgets Flutter
|
||||
|
||||
#### Widgets principaux
|
||||
|
||||
1. **ChatScreen** : Écran principal d'une conversation
|
||||
|
||||
```dart
|
||||
ChatScreen({
|
||||
required String conversationId,
|
||||
String? title,
|
||||
Widget? header,
|
||||
Widget? footer,
|
||||
bool enableAttachments = true,
|
||||
bool showTypingIndicator = true,
|
||||
bool enableReadReceipts = true,
|
||||
bool isAnnouncement = false,
|
||||
bool canReply = true,
|
||||
})
|
||||
```
|
||||
|
||||
2. **ConversationsList** : Liste des conversations
|
||||
|
||||
```dart
|
||||
ConversationsList({
|
||||
List<ConversationModel>? conversations,
|
||||
bool loadFromHive = true,
|
||||
Function(ConversationModel)? onConversationSelected,
|
||||
bool showLastMessage = true,
|
||||
bool showUnreadCount = true,
|
||||
bool showAnnouncementBadge = true,
|
||||
bool showPinnedFirst = true,
|
||||
Widget? emptyStateWidget,
|
||||
})
|
||||
```
|
||||
|
||||
3. **MessageBubble** : Bulle de message
|
||||
|
||||
```dart
|
||||
MessageBubble({
|
||||
required MessageModel message,
|
||||
bool showSenderInfo = true,
|
||||
bool showTimestamp = true,
|
||||
bool showStatus = true,
|
||||
bool isAnnouncement = false,
|
||||
double maxWidth = 300,
|
||||
})
|
||||
```
|
||||
|
||||
4. **ChatInput** : Zone de saisie de message
|
||||
|
||||
```dart
|
||||
ChatInput({
|
||||
required Function(String) onSendText,
|
||||
Function(File)? onSendFile,
|
||||
Function(File)? onSendImage,
|
||||
bool enableAttachments = true,
|
||||
bool enabled = true,
|
||||
String hintText = 'Saisissez votre message...',
|
||||
String? disabledMessage = 'Vous ne pouvez pas répondre à cette annonce',
|
||||
int? maxLength,
|
||||
})
|
||||
```
|
||||
|
||||
5. **AnonymousChatStarter** : Widget pour démarrer un chat anonyme (Resalice)
|
||||
|
||||
```dart
|
||||
AnonymousChatStarter({
|
||||
required Function(String?) onChatStarted,
|
||||
bool requireName = false,
|
||||
bool requireEmail = false,
|
||||
String buttonLabel = 'Démarrer une conversation',
|
||||
Widget? customForm,
|
||||
})
|
||||
```
|
||||
|
||||
6. **AnnouncementComposer** : Widget pour créer des annonces (Geosector uniquement)
|
||||
|
||||
```dart
|
||||
AnnouncementComposer({
|
||||
required Function(Map<String, dynamic>) onSend,
|
||||
List<Map<String, dynamic>>? availableTargets,
|
||||
String? initialTitle,
|
||||
String? initialMessage,
|
||||
bool allowAttachments = true,
|
||||
bool allowPinning = true,
|
||||
List<String> replyPermissionOptions = const ['all', 'admins_only', 'sender_only', 'none'],
|
||||
String defaultReplyPermission = 'none',
|
||||
DateTime? expiryDate,
|
||||
bool isGeosector = true, // Active la sélection des destinataires
|
||||
})
|
||||
```
|
||||
|
||||
7. **AnnouncementTargetSelector** : Sélecteur de destinataires pour annonces (Geosector uniquement)
|
||||
|
||||
```dart
|
||||
AnnouncementTargetSelector({
|
||||
required Function(AudienceTargetModel) onTargetSelected,
|
||||
required List<EntityModel> availableEntities,
|
||||
bool showRoleFilter = true,
|
||||
bool showEntityFilter = true,
|
||||
String defaultRole = 'all',
|
||||
String defaultEntity = 'all',
|
||||
})
|
||||
```
|
||||
|
||||
8. **AnnouncementBanner** : Bannière pour afficher une annonce importante
|
||||
```dart
|
||||
AnnouncementBanner({
|
||||
required MessageModel announcement,
|
||||
required Function() onView,
|
||||
Function()? onDismiss,
|
||||
bool isDismissible = true,
|
||||
Duration? autoDismissAfter,
|
||||
Color? backgroundColor,
|
||||
Widget? icon,
|
||||
})
|
||||
```
|
||||
|
||||
#### Fonctionnalités des widgets
|
||||
|
||||
- Design adaptatif (mobile/web)
|
||||
- Support des thèmes clairs/sombres
|
||||
- Gestion des messages non lus
|
||||
- Indicateurs de frappe
|
||||
- Accusés de réception et de lecture
|
||||
- Support des pièces jointes (fichiers, images)
|
||||
- Recherche dans les conversations
|
||||
- Conversion d'utilisateurs anonymes en clients (Resalice)
|
||||
|
||||
### 5. Gestion des données locales (Hive)
|
||||
|
||||
#### Organisation des boîtes Hive
|
||||
|
||||
```dart
|
||||
// Noms des boîtes Hive
|
||||
static const String conversationsBoxName = 'chat_conversations';
|
||||
static const String messagesBoxName = 'chat_messages';
|
||||
static const String participantsBoxName = 'chat_participants';
|
||||
static const String anonymousUsersBoxName = 'chat_anonymous_users';
|
||||
```
|
||||
|
||||
#### Stratégie de synchronisation
|
||||
|
||||
1. **Ouverture sélective** : Ouverture des boîtes à la demande
|
||||
2. **Gestion de conflit** : Stratégie pour résoudre les conflits entre données locales et serveur
|
||||
3. **Nettoyage intelligent** : Suppression des messages anciens selon des règles configurables
|
||||
4. **Marqueurs de synchronisation** : Tracking des messages synchronisés/non-synchronisés
|
||||
|
||||
## Implémentation technique
|
||||
|
||||
### 1. Structure des repositories
|
||||
|
||||
```dart
|
||||
class ChatRepository {
|
||||
// Gestion des conversations
|
||||
Future<List<ConversationModel>> getConversations({bool forceRefresh = false});
|
||||
Future<ConversationModel> getConversation(String id);
|
||||
Future<ConversationModel> createConversation(Map<String, dynamic> data);
|
||||
Future<void> deleteConversation(String id);
|
||||
Future<void> pinConversation(String id, bool isPinned);
|
||||
Future<void> updateReplyPermission(String id, String replyPermission);
|
||||
|
||||
// Gestion des messages
|
||||
Future<List<MessageModel>> getMessages(String conversationId, {int page = 1, int limit = 50});
|
||||
Future<MessageModel> sendMessage(String conversationId, Map<String, dynamic> messageData);
|
||||
Future<void> markMessageAsRead(String messageId);
|
||||
|
||||
// Gestion des participants
|
||||
Future<void> addParticipant(String conversationId, Map<String, dynamic> participantData);
|
||||
Future<void> removeParticipant(String conversationId, String participantId);
|
||||
|
||||
// Gestion des utilisateurs anonymes (Resalice)
|
||||
Future<String> createAnonymousUser({String? name, String? email});
|
||||
Future<void> convertAnonymousToUser(String anonymousId, String userId);
|
||||
|
||||
// Gestion des annonces
|
||||
Future<List<ConversationModel>> getAnnouncements({bool forceRefresh = false});
|
||||
Future<ConversationModel> createAnnouncement(Map<String, dynamic> data);
|
||||
Future<Map<String, dynamic>> getAnnouncementStats(String conversationId);
|
||||
|
||||
// Gestion des cibles d'audience
|
||||
Future<List<Map<String, dynamic>>> getAvailableAudienceTargets();
|
||||
Future<void> addAudienceTarget(String conversationId, Map<String, dynamic> targetData);
|
||||
Future<void> removeAudienceTarget(String conversationId, String targetId);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Intégration avec l'API
|
||||
|
||||
```dart
|
||||
class ChatApiService {
|
||||
final String baseUrl;
|
||||
final String? authToken;
|
||||
|
||||
// Constructeur avec paramètres pour l'URL et l'authentification
|
||||
ChatApiService({
|
||||
required this.baseUrl,
|
||||
this.authToken,
|
||||
});
|
||||
|
||||
// Méthodes HTTP pour communiquer avec l'API
|
||||
Future<Map<String, dynamic>> fetchConversations();
|
||||
Future<Map<String, dynamic>> fetchMessages(String conversationId, {int page = 1, int limit = 50});
|
||||
Future<Map<String, dynamic>> createConversation(Map<String, dynamic> data);
|
||||
Future<Map<String, dynamic>> sendMessage(String conversationId, Map<String, dynamic> messageData);
|
||||
// ...autres méthodes
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Gestion hors ligne
|
||||
|
||||
```dart
|
||||
class OfflineQueueService {
|
||||
// Ajouter des opérations en attente
|
||||
Future<void> addPendingOperation(String operationType, Map<String, dynamic> data);
|
||||
|
||||
// Traiter les opérations en attente
|
||||
Future<void> processPendingOperations();
|
||||
|
||||
// Écouter les changements de connectivité
|
||||
void listenToConnectivityChanges();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Stockage des fichiers
|
||||
|
||||
Le système supportera le téléchargement et le partage de fichiers :
|
||||
|
||||
1. **Côté serveur** : Stockage dans un répertoire sécurisé avec restriction d'accès
|
||||
2. **Côté client** : Mise en cache des fichiers pour éviter des téléchargements redondants
|
||||
3. **Types supportés** : Images, documents, autres fichiers selon configuration
|
||||
|
||||
## Cas d'utilisation spécifiques
|
||||
|
||||
### 1. Geosector
|
||||
|
||||
- **Utilisateurs authentifiés uniquement**
|
||||
- **Groupes par équipe** avec administrateurs pour les communications internes
|
||||
- **Historique complet** des conversations
|
||||
- **Intégration avec la structure existante** des amicales et équipes
|
||||
- **Annonces et broadcasts**:
|
||||
- Super admin → tous les admins d'entités
|
||||
- Admin d'entité → tous les utilisateurs de son entité
|
||||
- Communications descendantes sans possibilité de réponse
|
||||
- Statistiques de lecture des annonces importantes
|
||||
- **Ciblage flexible des destinataires** :
|
||||
- Par entité (toutes ou une spécifique)
|
||||
- Par rôle (tous, membres, administrateurs)
|
||||
- Combinaison entité + rôle (ex: admins de l'entité 5)
|
||||
- Sélection via le widget `AnnouncementTargetSelector`
|
||||
|
||||
### 2. Resalice
|
||||
|
||||
- **Chats initiés par des anonymes**
|
||||
- **Conversation one-to-one uniquement** entre professionnel et client/prospect
|
||||
- **Conversion client** : Processus pour transformer un utilisateur anonyme en client référencé
|
||||
- **Conservation des historiques** après conversion
|
||||
- **Interface professionnelle** adaptée aux échanges client/professionnel
|
||||
- **Pas de fonctionnalité d'annonce** - uniquement des conversations directes
|
||||
- **Annonces non pertinentes** pour ce cas d'usage (pas de widget `AnnouncementTargetSelector`)
|
||||
|
||||
### Adaptations par projet
|
||||
|
||||
La solution de chat doit être adaptable selon le contexte :
|
||||
|
||||
1. **Configuration globale** : Un système de configuration permet de définir quelles fonctionnalités sont activées
|
||||
|
||||
```dart
|
||||
// Configuration pour Geosector
|
||||
const chatConfig = ChatConfig(
|
||||
enableAnnouncements: true,
|
||||
enableTargetSelection: true,
|
||||
showAnnouncementStats: true,
|
||||
defaultReplyPermission: 'none',
|
||||
);
|
||||
|
||||
// Configuration pour Resalice
|
||||
const chatConfig = ChatConfig(
|
||||
enableAnnouncements: false,
|
||||
enableTargetSelection: false,
|
||||
showAnnouncementStats: false,
|
||||
defaultReplyPermission: 'all',
|
||||
);
|
||||
```
|
||||
|
||||
2. **Interfaces conditionnelles** : Les widgets adaptent leur affichage selon la configuration
|
||||
|
||||
```dart
|
||||
// Dans AnnouncementComposer
|
||||
if (config.enableTargetSelection) {
|
||||
children.add(AnnouncementTargetSelector(...));
|
||||
}
|
||||
```
|
||||
|
||||
3. **Types de conversation limités** : La création de certains types de conversation est restreinte
|
||||
```dart
|
||||
// Dans Resalice, seuls les types one_to_one et anonymous sont autorisés
|
||||
if (!config.enableAnnouncements && type == 'announcement') {
|
||||
throw UnsupportedConversationType();
|
||||
}
|
||||
```
|
||||
|
||||
## Adaptabilité et extensibilité
|
||||
|
||||
### 1. Options de personnalisation
|
||||
|
||||
- **Thèmes** : Adaptation aux couleurs et styles de l'application
|
||||
- **Fonctionnalités** : Activation/désactivation de certaines fonctionnalités
|
||||
- **Comportements** : Configuration des notifications, comportement hors ligne, etc.
|
||||
|
||||
### 2. Extensions possibles
|
||||
|
||||
- **Chatbot** : Possibilité d'intégrer des réponses automatiques
|
||||
- **Transfert** : Transfert de conversations entre professionnels
|
||||
- **Intégration CRM** : Liaison avec des systèmes CRM pour le suivi client
|
||||
- **Analyse** : Statistiques sur les conversations, temps de réponse, etc.
|
||||
|
||||
## Étapes d'implémentation suggérées
|
||||
|
||||
1. **Phase 1 : Base du système** (3-4 semaines)
|
||||
|
||||
- Modèles de données et adaptateurs Hive
|
||||
- Configuration de l'API backend
|
||||
- Widgets de base pour affichage/envoi de messages
|
||||
- Structure de base pour les annonces et broadcasts
|
||||
|
||||
2. **Phase 2 : Fonctionnalités avancées** (2-3 semaines)
|
||||
|
||||
- Gestion hors ligne et synchronisation
|
||||
- Support des fichiers et images
|
||||
- Indicateurs de lecture et d'écriture
|
||||
- Système de ciblage d'audience pour les annonces
|
||||
|
||||
3. **Phase 3 : Cas spécifiques** (2-3 semaines)
|
||||
- Support des conversations anonymes (Resalice)
|
||||
- Groupes et permissions avancées (Geosector)
|
||||
- Statistiques de lecture des annonces
|
||||
- Interface administrateur pour les annonces globales
|
||||
- Intégration web complète
|
||||
|
||||
Le temps total d'implémentation pour Geosector est estimé à 6-9 semaines pour un développeur expérimenté en Flutter et PHP. L'adaptation ultérieure à Resalice devrait prendre environ 2-3 semaines supplémentaires grâce à la conception modulaire du système.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Cette solution de chat personnalisée offre un équilibre entre robustesse et simplicité d'intégration. Elle répond aux besoins spécifiques de vos applications tout en restant suffisamment flexible pour s'adapter à d'autres contextes.
|
||||
|
||||
Le système prend en charge non seulement les conversations classiques (one-to-one, groupes) mais aussi les communications de type annonce/broadcast où un administrateur peut communiquer des informations importantes à des groupes d'utilisateurs définis par rôle ou entité, avec ou sans possibilité de réponse. Cette fonctionnalité est particulièrement adaptée aux cas d'usage mentionnés pour Geosector, où l'admin général souhaite communiquer avec tous les admins d'entités, ou un admin d'entité avec tous les utilisateurs de son entité.
|
||||
|
||||
En développant cette solution en interne, vous gardez un contrôle total sur les fonctionnalités et l'expérience utilisateur, tout en assurant une cohérence avec le reste de vos applications. La conception modulaire et réutilisable permettra également un déploiement efficace sur vos différentes plateformes et applications.
|
||||
34
flutt/fix-web-assets.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script pour corriger le problème d'assets dans l'application web
|
||||
echo "🔍 Fixing assets structure for web deployment..."
|
||||
|
||||
# Création du dossier assets/assets/animations si inexistant
|
||||
mkdir -p build/web/assets/assets/animations
|
||||
|
||||
# Copie des animations depuis le répertoire source
|
||||
cp -r assets/animations/* build/web/assets/assets/animations/
|
||||
|
||||
echo "✅ Assets structure fixed!"
|
||||
|
||||
# Si besoin de redéployer sans reconstruire l'application
|
||||
if [ "$1" == "--deploy" ]; then
|
||||
# Définition des variables
|
||||
REMOTE_USER="root"
|
||||
REMOTE_HOST="87.98.163.161"
|
||||
SSH_KEY="/Users/pierre/.ssh/id_rsa_mbpi"
|
||||
REMOTE_PATH="/var/www/geosector"
|
||||
|
||||
echo "📤 Deploying fixed assets to server..."
|
||||
rsync -rltz \
|
||||
-e "ssh -i ${SSH_KEY}" \
|
||||
build/web/assets/ \
|
||||
${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/assets/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Deployment failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Assets deployed successfully!"
|
||||
fi
|
||||
125
flutt/fix_ios_build.sh
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de réinitialisation complète pour résoudre les problèmes de compilation iOS
|
||||
# Spécialement conçu pour résoudre l'erreur "No such module 'Flutter'"
|
||||
# Version 2.0 - Avec ajout automatique des chemins de recherche de frameworks
|
||||
|
||||
echo "🧹 Nettoyage complet de l'environnement iOS..."
|
||||
|
||||
# Se placer dans le répertoire du projet
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Supprimer les fichiers générés par Flutter
|
||||
echo "📦 Nettoyage des fichiers Flutter..."
|
||||
flutter clean
|
||||
|
||||
# Supprimer le cache pub
|
||||
echo "🗑️ Suppression du cache pub pour les plugins problématiques..."
|
||||
rm -rf ~/.pub-cache/hosted/pub.dev/connectivity_plus-*
|
||||
|
||||
# Supprimer les fichiers de CocoaPods
|
||||
echo "🗂️ Nettoyage des fichiers CocoaPods..."
|
||||
cd ios
|
||||
rm -rf Pods
|
||||
rm -rf .symlinks
|
||||
rm -f Podfile.lock
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData
|
||||
|
||||
# Supprimer le workspace Xcode (il sera recréé)
|
||||
echo "🔄 Suppression du workspace Xcode..."
|
||||
rm -rf Runner.xcworkspace
|
||||
|
||||
# Revenir au répertoire parent
|
||||
cd ..
|
||||
|
||||
# Récupérer les dépendances Flutter
|
||||
echo "📥 Récupération des dépendances Flutter..."
|
||||
flutter pub get
|
||||
|
||||
# Régénérer les fichiers iOS
|
||||
echo "🔨 Précaching des outils iOS..."
|
||||
flutter precache --ios --force
|
||||
|
||||
# Forcer la génération des plugins
|
||||
echo "🔌 Régénération des plugins..."
|
||||
flutter pub cache repair
|
||||
flutter pub get
|
||||
|
||||
# Réinstaller les pods avec des options supplémentaires
|
||||
echo "📲 Réinstallation des pods..."
|
||||
cd ios
|
||||
pod deintegrate
|
||||
pod cache clean --all
|
||||
pod repo update
|
||||
pod install --repo-update --verbose
|
||||
|
||||
# Ajouter automatiquement les chemins de recherche de frameworks
|
||||
echo "🔍 Ajout des chemins de recherche de frameworks..."
|
||||
|
||||
# Créer un fichier temporaire pour stocker les chemins de recherche
|
||||
cat > ios/add_framework_paths.rb << 'EOL'
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'xcodeproj'
|
||||
|
||||
# Ouvrir le projet
|
||||
project_path = 'Runner.xcodeproj'
|
||||
project = Xcodeproj::Project.open(project_path)
|
||||
|
||||
# Trouver la cible Runner
|
||||
target = project.targets.find { |t| t.name == 'Runner' }
|
||||
|
||||
# Parcourir toutes les configurations de build
|
||||
target.build_configurations.each do |config|
|
||||
# Obtenir les paramètres de build actuels
|
||||
build_settings = config.build_settings
|
||||
|
||||
# Définir les chemins de recherche de frameworks
|
||||
framework_search_paths = [
|
||||
'$(inherited)',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios"',
|
||||
'"${PODS_ROOT}/Flutter"',
|
||||
'"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter"'
|
||||
]
|
||||
|
||||
# Ajouter les chemins de recherche de frameworks
|
||||
build_settings['FRAMEWORK_SEARCH_PATHS'] = framework_search_paths
|
||||
|
||||
# Ajouter les chemins de recherche d'en-têtes
|
||||
header_search_paths = [
|
||||
'$(inherited)',
|
||||
'"${PODS_ROOT}/Flutter"',
|
||||
'"${PODS_CONFIGURATION_BUILD_DIR}"'
|
||||
]
|
||||
|
||||
build_settings['HEADER_SEARCH_PATHS'] = header_search_paths
|
||||
|
||||
# S'assurer que les modules sont activés
|
||||
build_settings['DEFINES_MODULE'] = 'YES'
|
||||
|
||||
# Désactiver le bitcode
|
||||
build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
|
||||
# Inclure tous les assets d'icônes
|
||||
build_settings['ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS'] = 'YES'
|
||||
|
||||
# Autres paramètres importants
|
||||
build_settings['SWIFT_VERSION'] = '5.0'
|
||||
build_settings['CLANG_ENABLE_MODULES'] = 'YES'
|
||||
end
|
||||
|
||||
# Enregistrer les modifications
|
||||
project.save
|
||||
|
||||
puts "✅ Chemins de recherche de frameworks ajoutés avec succès !"
|
||||
EOL
|
||||
|
||||
# Exécuter le script Ruby pour ajouter les chemins de recherche
|
||||
cd ios
|
||||
ruby add_framework_paths.rb
|
||||
cd ..
|
||||
|
||||
echo "✅ Réinitialisation iOS terminée ! Ouvrez le projet avec 'open ios/Runner.xcworkspace'"
|
||||
67
flutt/git-create-branch.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to create a new branch from main/origin
|
||||
|
||||
# Check if branch name is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: Branch name is required"
|
||||
echo "Usage: $0 <branch-name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Store branch name from parameter
|
||||
BRANCH_NAME=$1
|
||||
|
||||
# Ensure we have the latest from origin
|
||||
echo "Fetching latest changes from origin..."
|
||||
git fetch origin
|
||||
|
||||
# Check if we're already on main, if not switch to it
|
||||
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
|
||||
if [ "$CURRENT_BRANCH" != "main" ]; then
|
||||
echo "Switching to main branch..."
|
||||
git checkout main
|
||||
fi
|
||||
|
||||
# Pull latest changes from main
|
||||
echo "Pulling latest changes from main..."
|
||||
git pull origin main
|
||||
|
||||
# Create and checkout the new branch
|
||||
echo "Creating and checking out new branch: $BRANCH_NAME"
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
|
||||
# Stage all changes
|
||||
echo "Staging all changes..."
|
||||
git add .
|
||||
|
||||
# Ask if user wants to make an initial commit
|
||||
read -p "Do you want to make an initial commit? (Y/n): " COMMIT_CHOICE
|
||||
|
||||
# Default to Yes if Enter is pressed without input
|
||||
COMMIT_CHOICE=${COMMIT_CHOICE:-Y}
|
||||
|
||||
if [[ $COMMIT_CHOICE =~ ^[Yy]$ ]]; then
|
||||
# Ask for commit message
|
||||
read -p "Enter commit message: " COMMIT_MESSAGE
|
||||
|
||||
# Check if commit message is provided
|
||||
if [ -n "$COMMIT_MESSAGE" ]; then
|
||||
# Make the commit
|
||||
echo "Creating commit with message: '$COMMIT_MESSAGE'"
|
||||
git commit -m "$COMMIT_MESSAGE"
|
||||
|
||||
# Push to remote with upstream tracking
|
||||
echo "Pushing to origin and setting upstream tracking..."
|
||||
git push -u origin "$BRANCH_NAME"
|
||||
|
||||
echo "Branch '$BRANCH_NAME' has been pushed to origin with tracking."
|
||||
else
|
||||
echo "No commit message provided. Skipping commit."
|
||||
fi
|
||||
else
|
||||
echo "Skipping initial commit. You can commit changes later."
|
||||
fi
|
||||
|
||||
echo "Success! You are now on branch: $BRANCH_NAME"
|
||||
echo "Ready to start working!"
|
||||
76
flutt/git-merge.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if a branch name was provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "Error: Please provide the name of the branch to merge"
|
||||
echo "Usage: ./git-merge.sh branch_name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BRANCH_NAME=$1
|
||||
|
||||
# Check if the branch exists
|
||||
if ! git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
|
||||
echo "Error: Branch '$BRANCH_NAME' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display the steps that will be executed
|
||||
echo "=== Starting merge process ==="
|
||||
echo "1. Checkout to main"
|
||||
echo "2. Pull latest changes"
|
||||
echo "3. Merge branch $BRANCH_NAME"
|
||||
echo "4. Push to origin"
|
||||
echo "5. Delete local and remote branches"
|
||||
|
||||
# Ask for confirmation
|
||||
read -p "Do you want to continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Operation cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute commands
|
||||
echo -e "\n=== Checking out to main ==="
|
||||
git checkout main
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error during checkout to main"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n=== Pulling latest changes ==="
|
||||
git pull origin main
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error during pull"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n=== Merging branch $BRANCH_NAME ==="
|
||||
git merge $BRANCH_NAME
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error during merge. Please resolve conflicts manually"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n=== Pushing to origin ==="
|
||||
git push origin main
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error during push"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n=== Deleting local branch ==="
|
||||
git branch -d $BRANCH_NAME
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Warning: Unable to delete local branch"
|
||||
echo "If you are sure everything is properly merged, use: git branch -D $BRANCH_NAME"
|
||||
fi
|
||||
|
||||
echo -e "\n=== Deleting remote branch ==="
|
||||
git push origin --delete $BRANCH_NAME
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Warning: Unable to delete remote branch"
|
||||
fi
|
||||
|
||||
echo -e "\n=== Merge process completed successfully ==="
|
||||
34
flutt/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
**/dgph
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
26
flutt/ios/Flutter/AppFrameworkInfo.plist
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
2
flutt/ios/Flutter/Debug.xcconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "Generated.xcconfig"
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
2
flutt/ios/Flutter/Release.xcconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "Generated.xcconfig"
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
81
flutt/ios/Podfile
Normal file
@@ -0,0 +1,81 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# Spécifier la version minimale d'iOS pour Stripe Tap to Pay
|
||||
platform :ios, '15.4'
|
||||
|
||||
# Ignorer les avertissements des pods
|
||||
install! 'cocoapods', :warn_for_unused_master_specs_repo => false
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
# Utiliser les frameworks dynamiques
|
||||
use_frameworks!
|
||||
|
||||
# Désactiver les en-têtes modulaires pour éviter les conflits
|
||||
# use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
# Configuration post-installation
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
# Maintenir la version minimale iOS 15.4 pour Stripe Tap to Pay
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.4'
|
||||
|
||||
# Désactiver Bitcode (recommandé par Flutter)
|
||||
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
|
||||
# Paramètres pour la compatibilité avec Xcode récent
|
||||
config.build_settings['ENABLE_USER_SCRIPT_SANDBOXING'] = 'NO'
|
||||
config.build_settings['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO'
|
||||
|
||||
# Paramètres pour éviter les erreurs de module
|
||||
config.build_settings['DEFINES_MODULE'] = 'YES'
|
||||
config.build_settings['SWIFT_VERSION'] = '5.0'
|
||||
|
||||
# Désactiver le support Mac Catalyst
|
||||
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
|
||||
|
||||
# Paramètres de signature de code
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
|
||||
# Ajout des permissions de géolocalisation
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
|
||||
'$(inherited)',
|
||||
'PERMISSION_LOCATION=1',
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
# Flutter post install
|
||||
flutter_post_install(installer) if defined?(flutter_post_install)
|
||||
end
|
||||
42
flutt/ios/Podfile.lock
Normal file
@@ -0,0 +1,42 @@
|
||||
PODS:
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- ReachabilitySwift
|
||||
- Flutter (1.0.0)
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift (5.2.4)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- ReachabilitySwift
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
|
||||
PODFILE CHECKSUM: f0d28569a754ac33c3d750271af244edf72e3a3c
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
814
flutt/ios/Runner.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,814 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
B29AD2EBEFD19B161772B50D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54642C142BC98D17D428B51D /* Pods_Runner.framework */; };
|
||||
C89DA9B9EA30824E0E881287 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EE1328CE0A8907C5568E72D /* Pods_RunnerTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
132FE5584808793FE93F08F5 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
21F13E510138E0DBAAA0667E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3DE8EBA41425E2A096EE70CF /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
3EE1328CE0A8907C5568E72D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54642C142BC98D17D428B51D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
8814F9792D6E6BA0874B431C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
CE8A95C455B844D61A15C99F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
FE152E3AEF93B264AE11B5E9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
9491A6C7DD10151C405FF968 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C89DA9B9EA30824E0E881287 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B29AD2EBEFD19B161772B50D /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5301A26C8AA9F29008B3D808 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54642C142BC98D17D428B51D /* Pods_Runner.framework */,
|
||||
3EE1328CE0A8907C5568E72D /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
C67A4583967DEDA799C193DE /* Pods */,
|
||||
5301A26C8AA9F29008B3D808 /* Frameworks */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C67A4583967DEDA799C193DE /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8814F9792D6E6BA0874B431C /* Pods-Runner.debug.xcconfig */,
|
||||
CE8A95C455B844D61A15C99F /* Pods-Runner.release.xcconfig */,
|
||||
FE152E3AEF93B264AE11B5E9 /* Pods-Runner.profile.xcconfig */,
|
||||
3DE8EBA41425E2A096EE70CF /* Pods-RunnerTests.debug.xcconfig */,
|
||||
21F13E510138E0DBAAA0667E /* Pods-RunnerTests.release.xcconfig */,
|
||||
132FE5584808793FE93F08F5 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
04F44EDE70DDFF90BCE6241F /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
9491A6C7DD10151C405FF968 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
9413D06037CA6133CC0A13EB /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
625AB1A439E96A5838DD474D /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1630;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
preferredProjectObjectVersion = 77;
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
04F44EDE70DDFF90BCE6241F /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
625AB1A439E96A5838DD474D /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9413D06037CA6133CC0A13EB /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 6WT84NWCTC;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios\"",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}\"",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = GEOSECTOR;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.2.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3DE8EBA41425E2A096EE70CF /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app.geosectorApp.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 21F13E510138E0DBAAA0667E /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app.geosectorApp.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 132FE5584808793FE93F08F5 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app.geosectorApp.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 6WT84NWCTC;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios\"",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}\"",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = GEOSECTOR;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.2.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 6WT84NWCTC;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios\"",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter\"",
|
||||
);
|
||||
"FRAMEWORK_SEARCH_PATHS[arch=*]" = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/connectivity_plus\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_ROOT}/Flutter\"",
|
||||
"\"${PODS_CONFIGURATION_BUILD_DIR}\"",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = GEOSECTOR;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.2.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.geosector.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
7
flutt/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1630"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||
BuildableName = "RunnerTests.xctest"
|
||||
BlueprintName = "RunnerTests"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Profile"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
10
flutt/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
13
flutt/ios/Runner/AppDelegate.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"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" : "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" : "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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
23
flutt/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
flutt/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
flutt/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
flutt/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
flutt/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Launch Screen Assets
|
||||
|
||||
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||
|
||||
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||
37
flutt/ios/Runner/Base.lproj/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
</resources>
|
||||
</document>
|
||||
26
flutt/ios/Runner/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
55
flutt/ios/Runner/Info.plist
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Geosector App</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>geosector_app</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Cette application nécessite l'accès à votre position pour enregistrer les passages et assurer le suivi des secteurs géographiques.</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Cette application nécessite l'accès à votre position pour enregistrer les passages et assurer le suivi des secteurs géographiques.</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>Cette application nécessite l'accès à votre position pour enregistrer les passages et assurer le suivi des secteurs géographiques.</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
1
flutt/ios/Runner/Runner-Bridging-Header.h
Normal file
@@ -0,0 +1 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
12
flutt/ios/RunnerTests/RunnerTests.swift
Normal file
@@ -0,0 +1,12 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
||||
32
flutt/ios_reset.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Se placer dans le répertoire du projet
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Supprimer les fichiers générés par Flutter
|
||||
flutter clean
|
||||
|
||||
# Supprimer les fichiers de CocoaPods
|
||||
cd ios
|
||||
rm -rf Pods
|
||||
rm -rf .symlinks
|
||||
rm -f Podfile.lock
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData
|
||||
|
||||
# Supprimer le workspace Xcode (il sera recréé)
|
||||
rm -rf Runner.xcworkspace
|
||||
|
||||
# Revenir au répertoire parent
|
||||
cd ..
|
||||
|
||||
# Récupérer les dépendances Flutter
|
||||
flutter pub get
|
||||
|
||||
# Régénérer les fichiers iOS
|
||||
flutter precache --ios
|
||||
|
||||
# Réinstaller les pods
|
||||
cd ios
|
||||
pod install --repo-update
|
||||
|
||||
echo "Réinitialisation iOS terminée !"
|
||||
214
flutt/lib/app.dart
Normal file
@@ -0,0 +1,214 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geosector_app/core/theme/app_theme.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/repositories/user_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/operation_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/passage_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/sector_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/membre_repository.dart';
|
||||
import 'package:geosector_app/core/services/sync_service.dart';
|
||||
import 'package:geosector_app/core/services/connectivity_service.dart';
|
||||
import 'package:geosector_app/presentation/auth/splash_page.dart';
|
||||
import 'package:geosector_app/presentation/public/landing_page.dart';
|
||||
import 'package:geosector_app/presentation/auth/login_page.dart';
|
||||
import 'package:geosector_app/presentation/auth/register_page.dart';
|
||||
import 'package:geosector_app/presentation/admin/admin_dashboard_page.dart';
|
||||
import 'package:geosector_app/presentation/user/user_dashboard_page.dart';
|
||||
|
||||
// Instances globales des services et repositories
|
||||
final apiService = ApiService();
|
||||
final operationRepository = OperationRepository(apiService);
|
||||
final passageRepository = PassageRepository(apiService);
|
||||
final userRepository = UserRepository(apiService);
|
||||
final sectorRepository = SectorRepository(apiService);
|
||||
final membreRepository = MembreRepository(apiService);
|
||||
final syncService = SyncService(userRepository: userRepository);
|
||||
final connectivityService = ConnectivityService();
|
||||
|
||||
class GeoSectorApp extends StatelessWidget {
|
||||
const GeoSectorApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Utiliser directement le router sans provider
|
||||
final router = GoRouter(
|
||||
initialLocation: '/',
|
||||
debugLogDiagnostics: true,
|
||||
refreshListenable:
|
||||
userRepository, // Écouter les changements d'état d'authentification
|
||||
redirect: (context, state) {
|
||||
// Sauvegarder le chemin actuel pour l'utilisateur connecté, sauf pour la page de splash
|
||||
if (state.uri.toString() != '/' && userRepository.isLoggedIn) {
|
||||
// Ne pas sauvegarder les chemins de login/register
|
||||
if (!state.uri.toString().startsWith('/login') &&
|
||||
!state.uri.toString().startsWith('/register') &&
|
||||
!state.uri.toString().startsWith('/public')) {
|
||||
userRepository.updateLastPath(state.uri.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier si l'utilisateur est sur la page de splash
|
||||
if (state.uri.toString() == '/') {
|
||||
// Vérifier si l'utilisateur a une session valide
|
||||
final currentUser = userRepository.getCurrentUser();
|
||||
if (currentUser == null || currentUser.sessionId == null) {
|
||||
// Si pas de session valide, rediriger vers la landing page
|
||||
return '/public';
|
||||
}
|
||||
|
||||
// Si l'utilisateur a une session valide et un chemin précédent, y retourner
|
||||
final lastPath = userRepository.getLastPath();
|
||||
if (lastPath != null && lastPath.isNotEmpty) {
|
||||
return lastPath;
|
||||
}
|
||||
|
||||
// Sinon, rediriger vers le tableau de bord approprié
|
||||
if (userRepository.isAdmin()) {
|
||||
return '/admin';
|
||||
} else {
|
||||
return '/user';
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier si l'utilisateur est sur une page d'authentification
|
||||
final isLoggedIn = userRepository.isLoggedIn;
|
||||
final isOnLoginPage = state.uri.toString() == '/login';
|
||||
final isOnRegisterPage = state.uri.toString() == '/register';
|
||||
final isOnAdminRegisterPage = state.uri.toString() == '/admin-register';
|
||||
final isOnPublicPage = state.uri.toString() == '/public';
|
||||
|
||||
// Vérifier si l'utilisateur vient de la landing page et va vers la page de connexion
|
||||
// Cette information est stockée dans les paramètres de la route
|
||||
final isFromLandingPage =
|
||||
state.uri.queryParameters['from'] == 'landing';
|
||||
|
||||
// Permettre l'accès aux pages publiques sans authentification
|
||||
if (isOnPublicPage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Si l'utilisateur vient de la landing page et va vers la page de connexion ou d'inscription,
|
||||
// ne pas rediriger, même s'il est déjà connecté
|
||||
if ((isOnLoginPage || isOnRegisterPage) && isFromLandingPage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Si l'utilisateur n'est pas connecté et n'est pas sur une page d'authentification, rediriger vers la page de connexion
|
||||
if (!isLoggedIn &&
|
||||
!isOnLoginPage &&
|
||||
!isOnRegisterPage &&
|
||||
!isOnAdminRegisterPage) {
|
||||
return '/login';
|
||||
}
|
||||
|
||||
// Si l'utilisateur est connecté et se trouve sur une page d'authentification, rediriger vers le tableau de bord approprié
|
||||
if (isLoggedIn &&
|
||||
(isOnLoginPage || isOnRegisterPage || isOnAdminRegisterPage)) {
|
||||
if (userRepository.isAdmin()) {
|
||||
return '/admin';
|
||||
} else {
|
||||
return '/user';
|
||||
}
|
||||
}
|
||||
|
||||
// Si l'utilisateur est connecté en tant qu'administrateur mais essaie d'accéder à une page utilisateur, rediriger vers le tableau de bord admin
|
||||
if (isLoggedIn &&
|
||||
userRepository.isAdmin() &&
|
||||
state.uri.toString().startsWith('/user')) {
|
||||
return '/admin';
|
||||
}
|
||||
|
||||
// Si l'utilisateur est connecté en tant qu'utilisateur mais essaie d'accéder à une page admin, rediriger vers le tableau de bord utilisateur
|
||||
if (isLoggedIn &&
|
||||
!userRepository.isAdmin() &&
|
||||
state.uri.toString().startsWith('/admin')) {
|
||||
return '/user';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
routes: [
|
||||
// Splash screen et page de démarrage
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => const SplashPage(),
|
||||
),
|
||||
|
||||
// Pages publiques
|
||||
GoRoute(
|
||||
path: '/public',
|
||||
builder: (context, state) => const LandingPage(),
|
||||
),
|
||||
|
||||
// Pages d'authentification
|
||||
GoRoute(
|
||||
path: '/login',
|
||||
builder: (context, state) {
|
||||
// Extraire le type de connexion depuis les extras
|
||||
Map<String, dynamic>? extras;
|
||||
if (state.extra != null && state.extra is Map<String, dynamic>) {
|
||||
extras = state.extra as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
String? loginType = extras?['type'];
|
||||
print('DEBUG ROUTER: Type dans les extras: $loginType');
|
||||
|
||||
// Nettoyer le paramètre type si présent
|
||||
if (loginType != null) {
|
||||
loginType = loginType.trim().toLowerCase();
|
||||
print('DEBUG ROUTER: Type nettoyé: $loginType');
|
||||
} else {
|
||||
// Fallback: essayer de récupérer depuis les paramètres d'URL
|
||||
final queryParams = state.uri.queryParameters;
|
||||
loginType = queryParams['type'];
|
||||
if (loginType != null) {
|
||||
loginType = loginType.trim().toLowerCase();
|
||||
print('DEBUG ROUTER: Type récupéré des params URL: $loginType');
|
||||
} else {
|
||||
loginType = 'admin'; // Valeur par défaut
|
||||
print('DEBUG ROUTER: Type par défaut: admin');
|
||||
}
|
||||
}
|
||||
|
||||
return LoginPage(
|
||||
key: Key('login_page_${loginType}'),
|
||||
loginType: loginType,
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/register',
|
||||
builder: (context, state) => const RegisterPage(),
|
||||
),
|
||||
|
||||
// Pages administrateur
|
||||
GoRoute(
|
||||
path: '/admin',
|
||||
builder: (context, state) => const AdminDashboardPage(),
|
||||
routes: [
|
||||
// Ajouter d'autres routes admin ici
|
||||
],
|
||||
),
|
||||
|
||||
// Pages utilisateur
|
||||
GoRoute(
|
||||
path: '/user',
|
||||
builder: (context, state) => const UserDashboardPage(),
|
||||
routes: [
|
||||
// Ajouter d'autres routes utilisateur ici
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'GEOSECTOR',
|
||||
theme: AppTheme.lightTheme,
|
||||
darkTheme: AppTheme.darkTheme,
|
||||
themeMode: ThemeMode.system,
|
||||
routerConfig: router,
|
||||
);
|
||||
}
|
||||
}
|
||||
82
flutt/lib/chat/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Module Chat GEOSECTOR
|
||||
|
||||
## Structure du module
|
||||
|
||||
Le module chat est organisé selon une architecture modulaire respectant la séparation des préoccupations :
|
||||
|
||||
```
|
||||
lib/chat/
|
||||
├── models/ # Modèles de données
|
||||
│ ├── conversation_model.dart
|
||||
│ ├── message_model.dart
|
||||
│ ├── participant_model.dart
|
||||
│ └── audience_target_model.dart
|
||||
├── repositories/ # Gestion des données
|
||||
│ └── chat_repository.dart
|
||||
├── services/ # Services techniques
|
||||
│ ├── chat_api_service.dart
|
||||
│ └── offline_queue_service.dart
|
||||
├── widgets/ # Composants UI
|
||||
│ ├── chat_screen.dart
|
||||
│ ├── conversations_list.dart
|
||||
│ ├── message_bubble.dart
|
||||
│ └── chat_input.dart
|
||||
├── pages/ # Pages de l'application
|
||||
│ └── chat_page.dart
|
||||
├── chat.dart # Point d'entrée avec exports
|
||||
└── README.md # Documentation du module
|
||||
```
|
||||
|
||||
## Fonctionnalités principales
|
||||
|
||||
1. **Conversations** : Support des conversations one-to-one, groupes et annonces
|
||||
2. **Messages** : Envoi/réception de messages texte et pièces jointes
|
||||
3. **Participants** : Gestion des participants aux conversations
|
||||
4. **Annonces** : Diffusion de messages à des groupes spécifiques
|
||||
5. **Mode hors ligne** : File d'attente pour la synchronisation des données
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Importation
|
||||
|
||||
```dart
|
||||
import 'package:geosector/chat/chat.dart';
|
||||
```
|
||||
|
||||
### Affichage de la page chat
|
||||
|
||||
```dart
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const ChatPage()),
|
||||
);
|
||||
```
|
||||
|
||||
### Création d'une conversation
|
||||
|
||||
```dart
|
||||
final chatRepository = ChatRepository();
|
||||
final conversation = await chatRepository.createConversation({
|
||||
'type': 'one_to_one',
|
||||
'participants': [userId1, userId2],
|
||||
});
|
||||
```
|
||||
|
||||
## États d'implémentation
|
||||
|
||||
- [x] Structure de base
|
||||
- [ ] Modèles de données complets
|
||||
- [ ] Intégration avec Hive
|
||||
- [ ] Services API
|
||||
- [ ] Gestion hors ligne
|
||||
- [ ] Widgets visuels
|
||||
- [ ] Tests unitaires
|
||||
|
||||
## À faire
|
||||
|
||||
1. Compléter l'implémentation des modèles avec les adaptateurs Hive
|
||||
2. Implémenter les méthodes dans les services et repositories
|
||||
3. Créer les widgets visuels avec le design approprié
|
||||
4. Ajouter les adaptateurs Hive pour le stockage local
|
||||
5. Implémenter la gestion des pièces jointes
|
||||
6. Ajouter les tests unitaires
|
||||
35
flutt/lib/chat/chat.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
/// Exportation principale du module chat
|
||||
///
|
||||
/// Ce fichier centralise les exportations du module chat
|
||||
/// pour faciliter l'importation dans d'autres parties de l'application
|
||||
|
||||
// Models
|
||||
export 'models/conversation_model.dart';
|
||||
export 'models/message_model.dart';
|
||||
export 'models/participant_model.dart';
|
||||
export 'models/audience_target_model.dart';
|
||||
export 'models/anonymous_user_model.dart';
|
||||
export 'models/chat_config.dart';
|
||||
export 'models/notification_settings.dart';
|
||||
|
||||
// Repositories
|
||||
export 'repositories/chat_repository.dart';
|
||||
|
||||
// Services
|
||||
export 'services/chat_api_service.dart';
|
||||
export 'services/offline_queue_service.dart';
|
||||
export 'services/notifications/mqtt_notification_service.dart';
|
||||
export 'services/notifications/mqtt_config.dart';
|
||||
|
||||
// Widgets
|
||||
export 'widgets/chat_screen.dart';
|
||||
export 'widgets/conversations_list.dart';
|
||||
export 'widgets/message_bubble.dart';
|
||||
export 'widgets/chat_input.dart';
|
||||
export 'widgets/notification_settings_widget.dart';
|
||||
|
||||
// Pages
|
||||
export 'pages/chat_page.dart';
|
||||
|
||||
// Constants
|
||||
export 'constants/chat_constants.dart';
|
||||
510
flutt/lib/chat/chat_updated.md
Normal file
@@ -0,0 +1,510 @@
|
||||
# Solution de Chat pour Applications Flutter
|
||||
|
||||
## Présentation générale
|
||||
|
||||
Cette solution propose un système de chat personnalisé et autonome pour des applications Flutter, avec possibilité d'intégration web. Elle est conçue pour fonctionner dans deux contextes différents :
|
||||
|
||||
1. **Chat entre utilisateurs authentifiés** (cas Geosector) : communications one-to-one ou en groupe entre utilisateurs déjà enregistrés dans la base de données.
|
||||
2. **Chat entre professionnels et visiteurs anonymes** (cas Resalice) : communications initiées par des visiteurs anonymes qui peuvent ensuite être convertis en clients référencés.
|
||||
|
||||
## Architecture technique
|
||||
|
||||
### 1. Structure générale
|
||||
|
||||
La solution s'articule autour de quatre composants principaux :
|
||||
|
||||
- **Module Flutter** : Widgets et logique pour l'interface utilisateur mobile
|
||||
- **Module Web** : Composants pour l'intégration web (compatible avec Flutter Web ou sites traditionnels)
|
||||
- **API Backend** : Endpoints REST uniquement pour la récupération de l'historique des conversations
|
||||
- **Module Go Chat Service** : Service de gestion des messages MQTT, modération et synchronisation avec la base de données
|
||||
|
||||
### 2. Infrastructure de notifications
|
||||
|
||||
#### Broker MQTT
|
||||
Le système utilise MQTT pour les notifications en temps réel :
|
||||
- Broker Mosquitto hébergé dans un container Incus
|
||||
- Connexion sécurisée via SSL/TLS (port 8883)
|
||||
- Authentification par username/password
|
||||
- QoS 1 (at least once) pour garantir la livraison
|
||||
|
||||
#### Module Go Chat Service
|
||||
Un service externe en Go qui :
|
||||
- Écoute les événements MQTT
|
||||
- Enregistre les messages dans la base de données
|
||||
- Applique des règles de modération configurables
|
||||
- Synchronise les notifications avec le stockage
|
||||
|
||||
```go
|
||||
type ChatService struct {
|
||||
mqttClient mqtt.Client
|
||||
db *sql.DB
|
||||
moderator *Moderator
|
||||
config *ChatConfig
|
||||
}
|
||||
|
||||
type ChatConfig struct {
|
||||
ApplicationID string
|
||||
ModeratorEnabled bool
|
||||
BadWords []string
|
||||
FloodLimits int
|
||||
SpamRules map[string]interface{}
|
||||
Webhooks []string
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Modèle de données
|
||||
|
||||
#### Entités principales
|
||||
|
||||
```
|
||||
Conversation
|
||||
├── id : Identifiant unique
|
||||
├── type : Type de conversation (one_to_one, group, anonymous, broadcast, announcement)
|
||||
├── title : Titre facultatif pour les groupes et obligatoire pour les annonces
|
||||
├── reply_permission : Niveau de permission pour répondre (all, admins_only, sender_only, none)
|
||||
├── created_at : Date de création
|
||||
├── updated_at : Dernière mise à jour
|
||||
├── is_pinned : Indique si la conversation est épinglée (pour annonces importantes)
|
||||
├── expiry_date : Date d'expiration optionnelle (pour annonces temporaires)
|
||||
└── participants : Liste des participants
|
||||
|
||||
Message
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── sender_id : ID de l'expéditeur (null pour anonyme)
|
||||
├── sender_type : Type d'expéditeur (user, anonymous, system)
|
||||
├── content : Contenu du message
|
||||
├── content_type : Type de contenu (text, image, file)
|
||||
├── created_at : Date d'envoi
|
||||
├── delivered_at : Date de réception
|
||||
├── read_at : Date de lecture
|
||||
├── status : Statut du message (sent, delivered, read, error)
|
||||
├── is_announcement : Indique s'il s'agit d'une annonce officielle
|
||||
├── is_moderated : Indique si le message a été modéré
|
||||
└── moderation_status : Statut de la modération (pending, approved, rejected)
|
||||
|
||||
Participant
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── user_id : ID de l'utilisateur (si authentifié)
|
||||
├── anonymous_id : ID anonyme (pour Resalice)
|
||||
├── role : Rôle (admin, member, read_only)
|
||||
├── joined_at : Date d'ajout à la conversation
|
||||
├── via_target : Indique si l'utilisateur est inclus via un AudienceTarget
|
||||
├── can_reply : Possibilité explicite de répondre (override de reply_permission)
|
||||
└── last_read_message_id : ID du dernier message lu
|
||||
|
||||
AudienceTarget
|
||||
├── id : Identifiant unique
|
||||
├── conversation_id : ID de la conversation
|
||||
├── target_type : Type de cible (role, entity, all, combined)
|
||||
├── target_id : ID du rôle ou de l'entité ciblée (pour compatibility)
|
||||
├── role_filter : Filtre de rôle pour le ciblage combiné ('all', '1', '2', etc.)
|
||||
├── entity_filter : Filtre d'entité pour le ciblage combiné ('all', 'id_entité')
|
||||
└── created_at : Date de création
|
||||
|
||||
AnonymousUser (pour Resalice)
|
||||
├── id : Identifiant unique
|
||||
├── device_id : Identifiant du dispositif
|
||||
├── name : Nom temporaire (si fourni)
|
||||
├── email : Email (si fourni)
|
||||
├── created_at : Date de création
|
||||
├── converted_to_user_id : ID utilisateur après conversion
|
||||
└── metadata : Informations supplémentaires
|
||||
|
||||
ChatNotification
|
||||
├── id : Identifiant unique
|
||||
├── user_id : ID de l'utilisateur destinataire
|
||||
├── message_id : ID du message
|
||||
├── conversation_id : ID de la conversation
|
||||
├── type : Type de notification
|
||||
├── status : Statut (sent, delivered, read)
|
||||
├── sent_at : Date d'envoi
|
||||
└── read_at : Date de lecture
|
||||
```
|
||||
|
||||
### 4. Backend et API
|
||||
|
||||
#### Structure de l'API
|
||||
|
||||
L'API sera développée en PHP 8.3 pour s'intégrer avec vos systèmes existants :
|
||||
|
||||
```
|
||||
/api/chat/conversations
|
||||
GET - Liste des conversations de l'utilisateur
|
||||
POST - Créer une nouvelle conversation
|
||||
|
||||
/api/chat/conversations/{id}
|
||||
GET - Détails d'une conversation
|
||||
PUT - Mettre à jour une conversation
|
||||
DELETE - Supprimer une conversation
|
||||
|
||||
/api/chat/conversations/{id}/messages
|
||||
GET - Messages d'une conversation (pagination) - uniquement pour l'historique
|
||||
|
||||
/api/chat/conversations/{id}/participants
|
||||
GET - Liste des participants
|
||||
POST - Ajouter un participant
|
||||
DELETE - Retirer un participant
|
||||
|
||||
/api/chat/messages/{id}
|
||||
PUT - Mettre à jour un message (ex: marquer comme lu)
|
||||
DELETE - Supprimer un message
|
||||
|
||||
/api/chat/anonymous
|
||||
POST - Démarrer une conversation anonyme
|
||||
|
||||
# Nouveaux endpoints pour les annonces
|
||||
/api/chat/announcements
|
||||
GET - Liste des annonces pour l'utilisateur
|
||||
POST - Créer une nouvelle annonce
|
||||
|
||||
/api/chat/announcements/{id}/stats
|
||||
GET - Obtenir les statistiques de lecture (qui a lu/non lu)
|
||||
|
||||
/api/chat/audience-targets
|
||||
GET - Obtenir les cibles disponibles pour l'utilisateur actuel
|
||||
|
||||
/api/chat/conversations/{id}/pin
|
||||
PUT - Épingler/désépingler une conversation
|
||||
|
||||
/api/chat/conversations/{id}/reply-permission
|
||||
PUT - Modifier les permissions de réponse
|
||||
|
||||
/api/chat/moderation/rules
|
||||
GET - Obtenir les règles de modération
|
||||
PUT - Mettre à jour les règles de modération
|
||||
```
|
||||
|
||||
#### Synchronisation
|
||||
|
||||
Le système supporte deux flux de données distincts :
|
||||
|
||||
1. **Temps réel via MQTT** :
|
||||
- Envoi de messages en temps réel
|
||||
- Notifications instantanées
|
||||
- Gestion via le module Go
|
||||
|
||||
2. **Récupération historique via REST** :
|
||||
- Chargement de l'historique des conversations
|
||||
- Synchronisation des anciens messages
|
||||
- Accès direct à la base de données
|
||||
|
||||
- Enregistrement local des messages avec Hive pour le fonctionnement hors ligne
|
||||
|
||||
### 5. Widgets Flutter
|
||||
|
||||
#### Widgets principaux
|
||||
|
||||
1. **ChatScreen** : Écran principal d'une conversation
|
||||
|
||||
```dart
|
||||
ChatScreen({
|
||||
required String conversationId,
|
||||
String? title,
|
||||
Widget? header,
|
||||
Widget? footer,
|
||||
bool enableAttachments = true,
|
||||
bool showTypingIndicator = true,
|
||||
bool enableReadReceipts = true,
|
||||
bool isAnnouncement = false,
|
||||
bool canReply = true,
|
||||
})
|
||||
```
|
||||
|
||||
2. **ConversationsList** : Liste des conversations
|
||||
|
||||
```dart
|
||||
ConversationsList({
|
||||
List<ConversationModel>? conversations,
|
||||
bool loadFromHive = true,
|
||||
Function(ConversationModel)? onConversationSelected,
|
||||
bool showLastMessage = true,
|
||||
bool showUnreadCount = true,
|
||||
bool showAnnouncementBadge = true,
|
||||
bool showPinnedFirst = true,
|
||||
Widget? emptyStateWidget,
|
||||
})
|
||||
```
|
||||
|
||||
3. **MessageBubble** : Bulle de message
|
||||
|
||||
```dart
|
||||
MessageBubble({
|
||||
required MessageModel message,
|
||||
bool showSenderInfo = true,
|
||||
bool showTimestamp = true,
|
||||
bool showStatus = true,
|
||||
bool isAnnouncement = false,
|
||||
double maxWidth = 300,
|
||||
})
|
||||
```
|
||||
|
||||
4. **ChatInput** : Zone de saisie de message
|
||||
|
||||
```dart
|
||||
ChatInput({
|
||||
required Function(String) onSendText,
|
||||
Function(File)? onSendFile,
|
||||
Function(File)? onSendImage,
|
||||
bool enableAttachments = true,
|
||||
bool enabled = true,
|
||||
String hintText = 'Saisissez votre message...',
|
||||
String? disabledMessage = 'Vous ne pouvez pas répondre à cette annonce',
|
||||
int? maxLength,
|
||||
})
|
||||
```
|
||||
|
||||
5. **AnonymousChatStarter** : Widget pour démarrer un chat anonyme (Resalice)
|
||||
|
||||
```dart
|
||||
AnonymousChatStarter({
|
||||
required Function(String?) onChatStarted,
|
||||
bool requireName = false,
|
||||
bool requireEmail = false,
|
||||
String buttonLabel = 'Démarrer une conversation',
|
||||
Widget? customForm,
|
||||
})
|
||||
```
|
||||
|
||||
6. **AnnouncementComposer** : Widget pour créer des annonces (Geosector uniquement)
|
||||
|
||||
```dart
|
||||
AnnouncementComposer({
|
||||
required Function(Map<String, dynamic>) onSend,
|
||||
List<Map<String, dynamic>>? availableTargets,
|
||||
String? initialTitle,
|
||||
String? initialMessage,
|
||||
bool allowAttachments = true,
|
||||
bool allowPinning = true,
|
||||
List<String> replyPermissionOptions = const ['all', 'admins_only', 'sender_only', 'none'],
|
||||
String defaultReplyPermission = 'none',
|
||||
DateTime? expiryDate,
|
||||
bool isGeosector = true, // Active la sélection des destinataires
|
||||
})
|
||||
```
|
||||
|
||||
### 6. Gestion des notifications MQTT
|
||||
|
||||
#### Service MQTT Flutter
|
||||
|
||||
```dart
|
||||
class MqttNotificationService {
|
||||
final String mqttHost;
|
||||
final int mqttPort;
|
||||
final String mqttUsername;
|
||||
final String mqttPassword;
|
||||
|
||||
Future<void> initialize({required String userId}) async {
|
||||
// Initialisation du client MQTT
|
||||
await _initializeMqttClient();
|
||||
// Abonnement aux topics de l'utilisateur
|
||||
_subscribeToUserTopics(userId);
|
||||
}
|
||||
|
||||
void _subscribeToUserTopics(String userId) {
|
||||
// Topics pour les messages personnels
|
||||
client.subscribe('chat/user/$userId/messages', MqttQos.atLeastOnce);
|
||||
// Topics pour les annonces
|
||||
client.subscribe('chat/announcement', MqttQos.atLeastOnce);
|
||||
}
|
||||
|
||||
Future<void> _handleMessage(String topic, Map<String, dynamic> data) async {
|
||||
// Traitement et affichage de la notification locale
|
||||
await _showLocalNotification(data);
|
||||
// Stockage local pour la synchronisation
|
||||
await _syncWithHive(data);
|
||||
}
|
||||
|
||||
// Pour envoyer un message en temps réel
|
||||
Future<void> sendMessage(String conversationId, String content) async {
|
||||
final message = {
|
||||
'conversationId': conversationId,
|
||||
'content': content,
|
||||
'senderId': currentUserId,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
};
|
||||
|
||||
await client.publishMessage(
|
||||
'chat/message/send',
|
||||
MqttQos.atLeastOnce,
|
||||
MqttClientPayloadBuilder().addString(jsonEncode(message)).payload!,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Service REST Flutter
|
||||
|
||||
```dart
|
||||
class ChatApiService {
|
||||
Future<List<Message>> getHistoricalMessages(
|
||||
String conversationId, {
|
||||
int page = 1,
|
||||
int limit = 50,
|
||||
}) async {
|
||||
final response = await get('/api/chat/conversations/$conversationId/messages');
|
||||
return (response.data as List)
|
||||
.map((json) => Message.fromJson(json))
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Note: Pas de POST pour les messages - uniquement pour l'historique
|
||||
}
|
||||
```
|
||||
|
||||
#### Structure des topics MQTT
|
||||
|
||||
```
|
||||
chat/user/{userId}/messages - Messages personnels
|
||||
chat/conversation/{convId} - Messages de groupe
|
||||
chat/announcement - Annonces générales
|
||||
chat/moderation/{msgId} - Résultats de modération
|
||||
chat/typing/{convId} - Indicateurs de frappe
|
||||
```
|
||||
|
||||
### 7. Module Go Chat Service
|
||||
|
||||
Le module Go gère :
|
||||
|
||||
1. **Réception MQTT**
|
||||
- Écoute les topics de chat
|
||||
- Parse les messages JSON
|
||||
- Valide le format
|
||||
|
||||
2. **Modération**
|
||||
- Analyse du contenu
|
||||
- Application des règles configurables
|
||||
- Filtrage des mots interdits
|
||||
- Détection de spam
|
||||
- Notification des résultats
|
||||
|
||||
3. **Synchronisation base de données**
|
||||
- Enregistrement des messages en base
|
||||
- Création des notifications
|
||||
- Mise à jour des statuts de livraison
|
||||
- Gestion des acquittements
|
||||
|
||||
**Note importante** : Le module Go n'a aucune interaction avec l'API REST. Il est uniquement connecté au broker MQTT pour recevoir les messages et à la base de données pour les stocker.
|
||||
|
||||
4. **Configuration par application**
|
||||
```yaml
|
||||
applications:
|
||||
geosector:
|
||||
moderator_enabled: true
|
||||
bad_words: ["liste", "des", "mots"]
|
||||
flood_limit: 5
|
||||
spam_rules:
|
||||
url_limit: 2
|
||||
repetition_threshold: 0.8
|
||||
resalice:
|
||||
moderator_enabled: false
|
||||
# Configuration différente
|
||||
```
|
||||
|
||||
### 8. Stockage des fichiers
|
||||
|
||||
Le système supportera le téléchargement et le partage de fichiers :
|
||||
|
||||
1. **Côté serveur** : Stockage dans un répertoire sécurisé avec restriction d'accès
|
||||
2. **Côté client** : Mise en cache des fichiers pour éviter des téléchargements redondants
|
||||
3. **Types supportés** : Images, documents, autres fichiers selon configuration
|
||||
|
||||
## Cas d'utilisation spécifiques
|
||||
|
||||
### 1. Geosector
|
||||
|
||||
- **Utilisateurs authentifiés uniquement**
|
||||
- **Groupes par équipe** avec administrateurs pour les communications internes
|
||||
- **Modération active** avec filtrage de contenu
|
||||
- **Historique complet** des conversations
|
||||
- **Intégration avec la structure existante** des amicales et équipes
|
||||
- **Annonces et broadcasts**:
|
||||
- Super admin → tous les admins d'entités
|
||||
- Admin d'entité → tous les utilisateurs de son entité
|
||||
- Communications descendantes sans possibilité de réponse
|
||||
- Statistiques de lecture des annonces importantes
|
||||
- **Ciblage flexible des destinataires** :
|
||||
- Par entité (toutes ou une spécifique)
|
||||
- Par rôle (tous, membres, administrateurs)
|
||||
- Combinaison entité + rôle (ex: admins de l'entité 5)
|
||||
- Sélection via le widget `AnnouncementTargetSelector`
|
||||
|
||||
### 2. Resalice
|
||||
|
||||
- **Chats initiés par des anonymes**
|
||||
- **Conversation one-to-one uniquement** entre professionnel et client/prospect
|
||||
- **Pas de modération active** par défaut
|
||||
- **Conversion client** : Processus pour transformer un utilisateur anonyme en client référencé
|
||||
- **Conservation des historiques** après conversion
|
||||
- **Interface professionnelle** adaptée aux échanges client/professionnel
|
||||
- **Pas de fonctionnalité d'annonce** - uniquement des conversations directes
|
||||
|
||||
## Adaptabilité et extensibilité
|
||||
|
||||
### 1. Options de personnalisation
|
||||
|
||||
- **Thèmes** : Adaptation aux couleurs et styles de l'application
|
||||
- **Fonctionnalités** : Activation/désactivation de certaines fonctionnalités
|
||||
- **Comportements** : Configuration des notifications, comportement hors ligne, etc.
|
||||
- **Modération** : Configuration par application
|
||||
|
||||
### 2. Extensions possibles
|
||||
|
||||
- **Chatbot** : Possibilité d'intégrer des réponses automatiques
|
||||
- **Transfert** : Transfert de conversations entre professionnels
|
||||
- **Intégration CRM** : Liaison avec des systèmes CRM pour le suivi client
|
||||
- **Analyse** : Statistiques sur les conversations, temps de réponse, etc.
|
||||
- **Audio/Vidéo** : Support des messages vocaux et vidéo
|
||||
|
||||
## Étapes d'implémentation suggérées
|
||||
|
||||
1. **Phase 1 : Infrastructure de base** (4-5 semaines)
|
||||
- Installation et configuration du broker MQTT
|
||||
- Développement du module Go Chat Service
|
||||
- Modèles de données et adaptateurs Hive
|
||||
- Configuration de l'API backend
|
||||
|
||||
2. **Phase 2 : Fonctionnalités principales** (4-5 semaines)
|
||||
- Widgets de base pour affichage/envoi de messages
|
||||
- Gestion des notifications MQTT
|
||||
- Système de modération
|
||||
- Structure de base pour les annonces et broadcasts
|
||||
|
||||
3. **Phase 3 : Fonctionnalités avancées** (3-4 semaines)
|
||||
- Gestion hors ligne et synchronisation
|
||||
- Support des fichiers et images
|
||||
- Indicateurs de lecture et d'écriture
|
||||
- Système de ciblage d'audience pour les annonces
|
||||
|
||||
4. **Phase 4 : Cas spécifiques** (3-4 semaines)
|
||||
- Support des conversations anonymes (Resalice)
|
||||
- Groupes et permissions avancées (Geosector)
|
||||
- Statistiques de lecture des annonces
|
||||
- Interface administrateur pour les annonces globales
|
||||
- Intégration web complète
|
||||
|
||||
Le temps total d'implémentation pour Geosector est estimé à 12-15 semaines pour un développeur expérimenté en Flutter, PHP et Go. L'adaptation ultérieure à Resalice devrait prendre environ 3-4 semaines supplémentaires grâce à la conception modulaire du système.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Cette solution de chat personnalisée offre un équilibre entre robustesse et simplicité d'intégration. Elle répond aux besoins spécifiques de vos applications tout en restant suffisamment flexible pour s'adapter à d'autres contextes.
|
||||
|
||||
Le système prend en charge non seulement les conversations classiques (one-to-one, groupes) mais aussi les communications de type annonce/broadcast où un administrateur peut communiquer des informations importantes à des groupes d'utilisateurs définis par rôle ou entité, avec ou sans possibilité de réponse.
|
||||
|
||||
### Points clés de l'architecture
|
||||
|
||||
1. **Séparation des flux** :
|
||||
- **Temps réel** : Via MQTT pour l'envoi de messages et les notifications
|
||||
- **Historique** : Via REST pour la récupération des anciennes conversations
|
||||
|
||||
2. **Modération centrée** : Le module Go gère la modération sans interaction avec l'API REST
|
||||
|
||||
3. **Auto-hébergement** :
|
||||
- Broker MQTT dans votre container Incus
|
||||
- Module Go dédié pour la gestion des messages
|
||||
- Contrôle total de l'infrastructure
|
||||
|
||||
4. **Configuration flexible** : Modération et comportement adaptables par application
|
||||
|
||||
En développant cette solution en interne, vous gardez un contrôle total sur les fonctionnalités et l'expérience utilisateur, tout en assurant une cohérence avec le reste de vos applications. La conception modulaire et réutilisable permettra également un déploiement efficace sur vos différentes plateformes et applications.
|
||||
50
flutt/lib/chat/constants/chat_constants.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
/// Constantes spécifiques au module chat
|
||||
|
||||
class ChatConstants {
|
||||
// Types de conversations
|
||||
static const String conversationTypeOneToOne = 'one_to_one';
|
||||
static const String conversationTypeGroup = 'group';
|
||||
static const String conversationTypeAnonymous = 'anonymous';
|
||||
static const String conversationTypeBroadcast = 'broadcast';
|
||||
static const String conversationTypeAnnouncement = 'announcement';
|
||||
|
||||
// Types de messages
|
||||
static const String messageTypeText = 'text';
|
||||
static const String messageTypeImage = 'image';
|
||||
static const String messageTypeFile = 'file';
|
||||
static const String messageTypeSystem = 'system';
|
||||
|
||||
// Types d'expéditeurs
|
||||
static const String senderTypeUser = 'user';
|
||||
static const String senderTypeAnonymous = 'anonymous';
|
||||
static const String senderTypeSystem = 'system';
|
||||
|
||||
// Rôles des participants
|
||||
static const String participantRoleAdmin = 'admin';
|
||||
static const String participantRoleMember = 'member';
|
||||
static const String participantRoleReadOnly = 'read_only';
|
||||
|
||||
// Permissions de réponse
|
||||
static const String replyPermissionAll = 'all';
|
||||
static const String replyPermissionAdminsOnly = 'admins_only';
|
||||
static const String replyPermissionSenderOnly = 'sender_only';
|
||||
static const String replyPermissionNone = 'none';
|
||||
|
||||
// Types de cibles d'audience
|
||||
static const String targetTypeRole = 'role';
|
||||
static const String targetTypeEntity = 'entity';
|
||||
static const String targetTypeAll = 'all';
|
||||
|
||||
// Noms des boîtes Hive
|
||||
static const String conversationsBoxName = 'chat_conversations';
|
||||
static const String messagesBoxName = 'chat_messages';
|
||||
static const String participantsBoxName = 'chat_participants';
|
||||
static const String anonymousUsersBoxName = 'chat_anonymous_users';
|
||||
static const String offlineQueueBoxName = 'chat_offline_queue';
|
||||
|
||||
// Configurations
|
||||
static const int defaultMessagePageSize = 50;
|
||||
static const int maxAttachmentSizeMB = 10;
|
||||
static const int maxMessageLength = 5000;
|
||||
static const Duration typingIndicatorTimeout = Duration(seconds: 3);
|
||||
}
|
||||