├── .gitignore
├── .metadata
├── CHANGELOG.md
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── ir_net
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── app_icon.png
├── globe.ico
├── globe_leaked.ico
├── iran.ico
├── kerio.png
├── loading.ico
├── network_error.ico
└── offline.ico
├── inno
├── Inno installer script.iss
└── installer license.txt
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── app.dart
├── bloc.dart
├── data
│ ├── leak_item.dart
│ └── shared_preferences.dart
├── home.dart
├── main.dart
├── utils
│ ├── cmd.dart
│ ├── http.dart
│ ├── kerio.dart
│ └── system_tray.dart
└── views
│ ├── connection.dart
│ ├── ip_stat.dart
│ ├── kerio_login.dart
│ ├── leak.dart
│ └── options.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── main.cc
├── my_application.cc
└── my_application.h
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── app_icon_1024.png
│ │ ├── app_icon_128.png
│ │ ├── app_icon_16.png
│ │ ├── app_icon_256.png
│ │ ├── app_icon_32.png
│ │ ├── app_icon_512.png
│ │ └── app_icon_64.png
│ ├── Base.lproj
│ └── MainMenu.xib
│ ├── Configs
│ ├── AppInfo.xcconfig
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
├── patches
└── Speed_test_in_web_view.patch
├── pubspec.lock
├── pubspec.yaml
├── screenshot.png
├── test
└── widget_test.dart
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── index.html
└── manifest.json
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 | /signing
35 |
36 | # Web related
37 | lib/generated_plugin_registrant.dart
38 |
39 | # Symbolication related
40 | app.*.symbols
41 |
42 | # Obfuscation related
43 | app.*.map.json
44 |
45 | # Android Studio will place build artifacts here
46 | /android/app/debug
47 | /android/app/profile
48 | /android/app/release
49 |
50 | # Inno
51 | /inno/Output
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
17 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
18 | - platform: android
19 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
20 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
21 | - platform: ios
22 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
23 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
24 | - platform: linux
25 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
26 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
27 | - platform: macos
28 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
29 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
30 | - platform: web
31 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
32 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
33 | - platform: windows
34 | create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
35 | base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.2.2
2 | - Add Kerio balance views
3 | - Show notification when Kerio balance is less than 1 GB
4 |
5 | # 1.2.1
6 | - Open kerio control page in the browser by clicking on end icon
7 |
8 | # 1.2.0
9 | - Integrate Kerio-Control login page
10 | - Show leaks on system tray by default
11 |
12 | # 1.1.0
13 | - Add speed test box
14 | - Set a fixed height and width when starting the app
15 | - Update window title
16 |
17 | # 1.0
18 | First official release
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ir_net
2 |
3 | Windows tool to show VPN connection details
4 |
5 |
6 |
7 | ## Features
8 | - Show location of connection in map
9 | - Leak detection on your urls
10 | - SysTray icon without the app being open
11 | - Start by windows startup
12 | - Ability to minimize and hide from taskbar
13 | - Show details of your ISP
14 | - Update status when there is a network change
15 | - Connect through proxy vpn types (eg. ShadowSocks, VMess, ...)
16 | - Auto Connect to Kerio Network
17 | - Show usage and statistics of Kerio network
18 |
19 | ## How to build windows installer
20 | 1. Build .exe file:
21 | ```bat
22 | flutter build windows
23 | ```
24 |
25 | 2. Open `Inno setup compiler` app and select .iss file from inno/Inno installer scrip.iss
26 | 3. Press on run button
27 | 4. Output .exe file will be in the `inno/Output` directory
28 |
29 | ## TODO
30 | - Add alternative api service
31 | - Choose default country and show flag based on that
32 | - Option to show all countries flag
33 | - Add statistics eg. (number of times and minutes there was a network error, reasons of network failure)
34 | - Add app launcher icon
35 | - Show error reason in leak detection list
36 | - Show which app occupied a port
37 | - Speed test
38 | - Shortcuts to important screens of windows (eg. Network adapters)
39 | - Retry one more time if there was a leak found during switch to new network
40 | - Reset ip lookup result when there is no network
41 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion flutter.compileSdkVersion
30 | ndkVersion flutter.ndkVersion
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += 'src/main/kotlin'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.example.ir_net"
48 | // You can update the following values to match your application needs.
49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
50 | minSdkVersion flutter.minSdkVersion
51 | targetSdkVersion flutter.targetSdkVersion
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | }
55 |
56 | buildTypes {
57 | release {
58 | // TODO: Add your own signing config for the release build.
59 | // Signing with the debug keys for now, so `flutter run --release` works.
60 | signingConfig signingConfigs.debug
61 | }
62 | }
63 | }
64 |
65 | flutter {
66 | source '../..'
67 | }
68 |
69 | dependencies {
70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
71 | }
72 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/ir_net/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.ir_net
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.1.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/app_icon.png
--------------------------------------------------------------------------------
/assets/globe.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/globe.ico
--------------------------------------------------------------------------------
/assets/globe_leaked.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/globe_leaked.ico
--------------------------------------------------------------------------------
/assets/iran.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/iran.ico
--------------------------------------------------------------------------------
/assets/kerio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/kerio.png
--------------------------------------------------------------------------------
/assets/loading.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/loading.ico
--------------------------------------------------------------------------------
/assets/network_error.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/network_error.ico
--------------------------------------------------------------------------------
/assets/offline.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/assets/offline.ico
--------------------------------------------------------------------------------
/inno/Inno installer script.iss:
--------------------------------------------------------------------------------
1 | ; Script generated by the Inno Setup Script Wizard.
2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3 |
4 | #define MyAppName "IRNet"
5 | #define MyAppVersion "1.2.2"
6 | #define MyAppPublisher "BuildToApp, Inc."
7 | #define MyAppURL "https://www.buildtoapp.com/"
8 | #define MyAppExeName "ir_net.exe"
9 |
10 | [Setup]
11 | ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
12 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
13 | AppId={{C4962B60-F5A8-4D6B-8BDD-8A83922270B5}
14 | AppName={#MyAppName}
15 | AppVersion={#MyAppVersion}
16 | ;AppVerName={#MyAppName} {#MyAppVersion}
17 | AppPublisher={#MyAppPublisher}
18 | AppPublisherURL={#MyAppURL}
19 | AppSupportURL={#MyAppURL}
20 | AppUpdatesURL={#MyAppURL}
21 | DefaultDirName={autopf}\{#MyAppName}
22 | ; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run
23 | ; on anything but x64 and Windows 11 on Arm.
24 | ArchitecturesAllowed=x64compatible
25 | ; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the
26 | ; install be done in "64-bit mode" on x64 or Windows 11 on Arm,
27 | ; meaning it should use the native 64-bit Program Files directory and
28 | ; the 64-bit view of the registry.
29 | ArchitecturesInstallIn64BitMode=x64compatible
30 | DisableProgramGroupPage=yes
31 | LicenseFile=C:\Workspace\Flutter\ir_net\inno\installer license.txt
32 | ; Uncomment the following line to run in non administrative install mode (install for current user only.)
33 | ;PrivilegesRequired=lowest
34 | OutputBaseFilename=IRNet_windows_setup
35 | Compression=lzma
36 | SolidCompression=yes
37 | WizardStyle=modern
38 |
39 | [Languages]
40 | Name: "english"; MessagesFile: "compiler:Default.isl"
41 |
42 | [Tasks]
43 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
44 |
45 | [Files]
46 | Source: "C:\Workspace\Flutter\ir_net\build\windows\x64\runner\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
47 | Source: "C:\Workspace\Flutter\ir_net\build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
48 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
49 |
50 | [Icons]
51 | Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
52 | Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
53 |
54 | [Run]
55 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
56 |
57 |
--------------------------------------------------------------------------------
/inno/installer license.txt:
--------------------------------------------------------------------------------
1 | End-User License Agreement (EULA) of IRNet
2 |
3 | This End-User License Agreement ("EULA") is a legal agreement between you and BuildToApp.
4 |
5 | This EULA agreement governs your acquisition and use of our IRNet software ("Software") directly from BuildToApp or indirectly through a BuildToApp authorized reseller or distributor (a "Reseller").
6 |
7 | Please read this EULA agreement carefully before completing the installation process and using the IRNet software. It provides a license to use the IRNet software and contains warranty information and liability disclaimers.
8 |
9 | By installing and/or using the IRNet software, you are confirming your acceptance of the Software and agreeing to become bound by the terms of this EULA agreement.
10 |
11 | If you are entering into this EULA agreement on behalf of a company or other legal entity, you represent that you have the authority to bind such entity to these terms. If you do not have such authority, or if you do not agree with the terms of this EULA agreement, do not install or use the Software, and you must not accept this EULA agreement.
12 |
13 | This EULA agreement shall apply only to the Software supplied by BuildToApp herewith regardless of whether other software is referred to or described herein. The terms also apply to any BuildToApp updates, supplements, Internet-based services, and support services for the Software unless other terms accompany those items on delivery. If so, those terms apply.
14 |
15 | License Grant
16 | BuildToApp hereby grants you a personal, non-transferable, non-exclusive license to use the IRNet software on your devices in accordance with the terms of this EULA agreement.
17 |
18 | You are permitted to load the IRNet software on a single computer or multiple devices (as agreed upon in your license purchase), under your control. You are responsible for ensuring your device meets the minimum requirements of the IRNet software.
19 |
20 | You are not permitted to:
21 |
22 | Edit, alter, modify, adapt, translate, or otherwise change the whole or any part of the Software, nor permit the whole or any part of the Software to be combined with or become incorporated into any other software, nor decompile, disassemble or reverse engineer the Software or attempt to do any such things.
23 | Reproduce, copy, distribute, resell, or otherwise use the Software for any commercial purpose.
24 | Allow any third party to use the Software on behalf of or for the benefit of any third party.
25 | Use the Software in any way that breaches any applicable local, national, or international law.
26 | Use the Software for any purpose that BuildToApp considers is a breach of this EULA agreement.
27 | Intellectual Property and Ownership
28 | BuildToApp shall at all times retain ownership of the Software as downloaded by you and all subsequent downloads of the Software. The Software (and the copyright, and other intellectual property rights of whatever nature in the Software, including any modifications made thereto) are and shall remain the property of BuildToApp.
29 |
30 | BuildToApp reserves the right to grant licenses to use the Software to third parties.
31 |
32 | Termination
33 | This EULA agreement is effective from the date you first use the Software and shall continue until terminated. You may terminate it at any time upon written notice to BuildToApp.
34 |
35 | It will also terminate immediately if you fail to comply with any term of this EULA agreement. Upon such termination, the licenses granted by this EULA agreement will immediately terminate, and you agree to stop all access and use of the Software. The provisions that by their nature continue and survive will survive any termination of this EULA agreement.
36 |
37 | Limitation of Liability
38 | To the maximum extent permitted by applicable law, in no event shall BuildToApp, its affiliates, licensors, or suppliers be liable for any special, incidental, indirect, or consequential damages whatsoever arising out of the use of or inability to use the Software (including, without limitation, damages for loss of profits, loss of data, business interruption, or any other pecuniary loss).
39 |
40 | Governing Law
41 | This EULA agreement, and any dispute arising out of or in connection with this EULA, shall be governed by and construed in accordance with the laws of the country, state, or jurisdiction in which BuildToApp is registered, without regard to its conflict of law provisions.
42 |
43 | Open Source Components
44 | Some components of the Software may be licensed under an open-source license, and the terms of the open-source licenses may override the terms of this EULA. You can find a list of these components and their licenses on the project’s official repository at: GitHub Repository of IRNet.
45 |
46 | Contact Information
47 | If you have any questions about this EULA, please contact BuildToApp at:
48 |
49 | Email: matthew.s@buildtoapp.com
50 | Address: Los Angles, U.S
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1300;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | );
177 | inputPaths = (
178 | );
179 | name = "Thin Binary";
180 | outputPaths = (
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | shellPath = /bin/sh;
184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
185 | };
186 | 9740EEB61CF901F6004384FC /* Run Script */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | inputPaths = (
192 | );
193 | name = "Run Script";
194 | outputPaths = (
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | shellPath = /bin/sh;
198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
199 | };
200 | /* End PBXShellScriptBuildPhase section */
201 |
202 | /* Begin PBXSourcesBuildPhase section */
203 | 97C146EA1CF9000F007C117D /* Sources */ = {
204 | isa = PBXSourcesBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | };
212 | /* End PBXSourcesBuildPhase section */
213 |
214 | /* Begin PBXVariantGroup section */
215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
216 | isa = PBXVariantGroup;
217 | children = (
218 | 97C146FB1CF9000F007C117D /* Base */,
219 | );
220 | name = Main.storyboard;
221 | sourceTree = "";
222 | };
223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
224 | isa = PBXVariantGroup;
225 | children = (
226 | 97C147001CF9000F007C117D /* Base */,
227 | );
228 | name = LaunchScreen.storyboard;
229 | sourceTree = "";
230 | };
231 | /* End PBXVariantGroup section */
232 |
233 | /* Begin XCBuildConfiguration section */
234 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_ANALYZER_NONNULL = YES;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
244 | CLANG_WARN_BOOL_CONVERSION = YES;
245 | CLANG_WARN_COMMA = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
249 | CLANG_WARN_EMPTY_BODY = YES;
250 | CLANG_WARN_ENUM_CONVERSION = YES;
251 | CLANG_WARN_INFINITE_RECURSION = YES;
252 | CLANG_WARN_INT_CONVERSION = YES;
253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
258 | CLANG_WARN_STRICT_PROTOTYPES = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNREACHABLE_CODE = YES;
261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu99;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | SDKROOT = iphoneos;
278 | SUPPORTED_PLATFORMS = iphoneos;
279 | TARGETED_DEVICE_FAMILY = "1,2";
280 | VALIDATE_PRODUCT = YES;
281 | };
282 | name = Profile;
283 | };
284 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
285 | isa = XCBuildConfiguration;
286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | CLANG_ENABLE_MODULES = YES;
290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
291 | ENABLE_BITCODE = NO;
292 | INFOPLIST_FILE = Runner/Info.plist;
293 | LD_RUNPATH_SEARCH_PATHS = (
294 | "$(inherited)",
295 | "@executable_path/Frameworks",
296 | );
297 | PRODUCT_BUNDLE_IDENTIFIER = com.example.irNet;
298 | PRODUCT_NAME = "$(TARGET_NAME)";
299 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
300 | SWIFT_VERSION = 5.0;
301 | VERSIONING_SYSTEM = "apple-generic";
302 | };
303 | name = Profile;
304 | };
305 | 97C147031CF9000F007C117D /* Debug */ = {
306 | isa = XCBuildConfiguration;
307 | buildSettings = {
308 | ALWAYS_SEARCH_USER_PATHS = NO;
309 | CLANG_ANALYZER_NONNULL = YES;
310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
311 | CLANG_CXX_LIBRARY = "libc++";
312 | CLANG_ENABLE_MODULES = YES;
313 | CLANG_ENABLE_OBJC_ARC = YES;
314 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
315 | CLANG_WARN_BOOL_CONVERSION = YES;
316 | CLANG_WARN_COMMA = YES;
317 | CLANG_WARN_CONSTANT_CONVERSION = YES;
318 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
320 | CLANG_WARN_EMPTY_BODY = YES;
321 | CLANG_WARN_ENUM_CONVERSION = YES;
322 | CLANG_WARN_INFINITE_RECURSION = YES;
323 | CLANG_WARN_INT_CONVERSION = YES;
324 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
325 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
326 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
327 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
328 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
329 | CLANG_WARN_STRICT_PROTOTYPES = YES;
330 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
331 | CLANG_WARN_UNREACHABLE_CODE = YES;
332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
334 | COPY_PHASE_STRIP = NO;
335 | DEBUG_INFORMATION_FORMAT = dwarf;
336 | ENABLE_STRICT_OBJC_MSGSEND = YES;
337 | ENABLE_TESTABILITY = YES;
338 | GCC_C_LANGUAGE_STANDARD = gnu99;
339 | GCC_DYNAMIC_NO_PIC = NO;
340 | GCC_NO_COMMON_BLOCKS = YES;
341 | GCC_OPTIMIZATION_LEVEL = 0;
342 | GCC_PREPROCESSOR_DEFINITIONS = (
343 | "DEBUG=1",
344 | "$(inherited)",
345 | );
346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
347 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
348 | GCC_WARN_UNDECLARED_SELECTOR = YES;
349 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
350 | GCC_WARN_UNUSED_FUNCTION = YES;
351 | GCC_WARN_UNUSED_VARIABLE = YES;
352 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
353 | MTL_ENABLE_DEBUG_INFO = YES;
354 | ONLY_ACTIVE_ARCH = YES;
355 | SDKROOT = iphoneos;
356 | TARGETED_DEVICE_FAMILY = "1,2";
357 | };
358 | name = Debug;
359 | };
360 | 97C147041CF9000F007C117D /* Release */ = {
361 | isa = XCBuildConfiguration;
362 | buildSettings = {
363 | ALWAYS_SEARCH_USER_PATHS = NO;
364 | CLANG_ANALYZER_NONNULL = YES;
365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
366 | CLANG_CXX_LIBRARY = "libc++";
367 | CLANG_ENABLE_MODULES = YES;
368 | CLANG_ENABLE_OBJC_ARC = YES;
369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
370 | CLANG_WARN_BOOL_CONVERSION = YES;
371 | CLANG_WARN_COMMA = YES;
372 | CLANG_WARN_CONSTANT_CONVERSION = YES;
373 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
375 | CLANG_WARN_EMPTY_BODY = YES;
376 | CLANG_WARN_ENUM_CONVERSION = YES;
377 | CLANG_WARN_INFINITE_RECURSION = YES;
378 | CLANG_WARN_INT_CONVERSION = YES;
379 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
380 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
381 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
384 | CLANG_WARN_STRICT_PROTOTYPES = YES;
385 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
386 | CLANG_WARN_UNREACHABLE_CODE = YES;
387 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
388 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
389 | COPY_PHASE_STRIP = NO;
390 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
391 | ENABLE_NS_ASSERTIONS = NO;
392 | ENABLE_STRICT_OBJC_MSGSEND = YES;
393 | GCC_C_LANGUAGE_STANDARD = gnu99;
394 | GCC_NO_COMMON_BLOCKS = YES;
395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
397 | GCC_WARN_UNDECLARED_SELECTOR = YES;
398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
399 | GCC_WARN_UNUSED_FUNCTION = YES;
400 | GCC_WARN_UNUSED_VARIABLE = YES;
401 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
402 | MTL_ENABLE_DEBUG_INFO = NO;
403 | SDKROOT = iphoneos;
404 | SUPPORTED_PLATFORMS = iphoneos;
405 | SWIFT_COMPILATION_MODE = wholemodule;
406 | SWIFT_OPTIMIZATION_LEVEL = "-O";
407 | TARGETED_DEVICE_FAMILY = "1,2";
408 | VALIDATE_PRODUCT = YES;
409 | };
410 | name = Release;
411 | };
412 | 97C147061CF9000F007C117D /* Debug */ = {
413 | isa = XCBuildConfiguration;
414 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
415 | buildSettings = {
416 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
417 | CLANG_ENABLE_MODULES = YES;
418 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
419 | ENABLE_BITCODE = NO;
420 | INFOPLIST_FILE = Runner/Info.plist;
421 | LD_RUNPATH_SEARCH_PATHS = (
422 | "$(inherited)",
423 | "@executable_path/Frameworks",
424 | );
425 | PRODUCT_BUNDLE_IDENTIFIER = com.example.irNet;
426 | PRODUCT_NAME = "$(TARGET_NAME)";
427 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
428 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
429 | SWIFT_VERSION = 5.0;
430 | VERSIONING_SYSTEM = "apple-generic";
431 | };
432 | name = Debug;
433 | };
434 | 97C147071CF9000F007C117D /* Release */ = {
435 | isa = XCBuildConfiguration;
436 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
437 | buildSettings = {
438 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
439 | CLANG_ENABLE_MODULES = YES;
440 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
441 | ENABLE_BITCODE = NO;
442 | INFOPLIST_FILE = Runner/Info.plist;
443 | LD_RUNPATH_SEARCH_PATHS = (
444 | "$(inherited)",
445 | "@executable_path/Frameworks",
446 | );
447 | PRODUCT_BUNDLE_IDENTIFIER = com.example.irNet;
448 | PRODUCT_NAME = "$(TARGET_NAME)";
449 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
450 | SWIFT_VERSION = 5.0;
451 | VERSIONING_SYSTEM = "apple-generic";
452 | };
453 | name = Release;
454 | };
455 | /* End XCBuildConfiguration section */
456 |
457 | /* Begin XCConfigurationList section */
458 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
459 | isa = XCConfigurationList;
460 | buildConfigurations = (
461 | 97C147031CF9000F007C117D /* Debug */,
462 | 97C147041CF9000F007C117D /* Release */,
463 | 249021D3217E4FDB00AE95B9 /* Profile */,
464 | );
465 | defaultConfigurationIsVisible = 0;
466 | defaultConfigurationName = Release;
467 | };
468 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
469 | isa = XCConfigurationList;
470 | buildConfigurations = (
471 | 97C147061CF9000F007C117D /* Debug */,
472 | 97C147071CF9000F007C117D /* Release */,
473 | 249021D4217E4FDB00AE95B9 /* Profile */,
474 | );
475 | defaultConfigurationIsVisible = 0;
476 | defaultConfigurationName = Release;
477 | };
478 | /* End XCConfigurationList section */
479 | };
480 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
481 | }
482 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Ir Net
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ir_net
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'home.dart';
4 |
5 | class App extends StatelessWidget {
6 | const App({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return MaterialApp(
11 | title: 'IRNet',
12 | debugShowCheckedModeBanner: false,
13 | theme: ThemeData(
14 | primarySwatch: Colors.blue,
15 | ),
16 | home: const HomePage(),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | import 'package:connectivity_plus/connectivity_plus.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:flutter_speedtest/flutter_speedtest.dart';
8 | import 'package:http/http.dart' as http;
9 | import 'package:http/io_client.dart';
10 | import 'package:ir_net/data/leak_item.dart';
11 | import 'package:ir_net/data/shared_preferences.dart';
12 | import 'package:ir_net/utils/cmd.dart';
13 | import 'package:ir_net/utils/http.dart';
14 | import 'package:ir_net/utils/system_tray.dart';
15 | import 'package:latlng/latlng.dart';
16 | import 'package:live_event/live_event.dart';
17 | import 'package:rxdart/rxdart.dart';
18 | import 'package:win_toast/win_toast.dart';
19 |
20 | import 'utils/kerio.dart';
21 |
22 | class AppBloc with AppSystemTray {
23 | final _latLng = StreamController();
24 | final _ipLookupResult = BehaviorSubject();
25 | final _clearLeakInput = LiveEvent();
26 | final _leakChecklist = BehaviorSubject>();
27 | final _localNetwork = BehaviorSubject();
28 | final _ping = BehaviorSubject();
29 | final _downloadSpeed = BehaviorSubject();
30 | final _uploadSpeed = BehaviorSubject();
31 | final _speedTestStatus = BehaviorSubject();
32 |
33 | bool _isPingingGoogle = false;
34 | bool _foundALeakedSite = false;
35 | String? _proxyServer;
36 | String? _leakInput;
37 |
38 | Stream get latLng => _latLng.stream;
39 | Stream get ipLookupResult => _ipLookupResult.stream;
40 | Stream get clearLeakInput => _clearLeakInput.stream;
41 | Stream> get leakChecklist => _leakChecklist.stream;
42 | Stream get localNetwork => _localNetwork.stream;
43 | Stream get ping => _ping.stream;
44 | Stream get downloadSpeed => _downloadSpeed.stream;
45 | Stream get uploadSpeed => _uploadSpeed.stream;
46 | Stream get speedTestStatus => _speedTestStatus.stream;
47 |
48 | final speedtest = FlutterSpeedtest(
49 | baseUrl: 'http://speedtest.jaosing.com:8080',
50 | pathDownload: '/download',
51 | pathUpload: '/upload',
52 | pathResponseTime: '/ping',
53 | );
54 |
55 | void onLeakInputChanged(String value) {
56 | _leakInput = value;
57 | }
58 |
59 | void initialize() {
60 | initSystemTray();
61 | _pingGoogle();
62 | _runIpCheckInfinitely();
63 | _runKerioCheckInfinitely();
64 | _subscribeConnectivityChange();
65 | _initializeLeakChecklist();
66 | }
67 |
68 | void _initializeLeakChecklist() async {
69 | await _updateLeakChecklist();
70 | _verifyLeakedSites();
71 | }
72 |
73 | void onDeleteLeakItemClick(LeakItem item) async {
74 | await AppSharedPreferences.removeFromLeakChecklist(item.url);
75 | _updateLeakChecklist();
76 | }
77 |
78 | void onAddLeakItemClick() async {
79 | if (_leakInput == null || _leakInput?.trim().isEmpty == true) {
80 | WinToast.instance().showToast(type: ToastType.text01, title: 'No input entered!');
81 | return;
82 | }
83 | if ((await AppSharedPreferences.leakChecklist).contains(_leakInput)) {
84 | WinToast.instance().showToast(type: ToastType.text01, title: 'Repetitive input not allowed!');
85 | return;
86 | }
87 | await AppSharedPreferences.addToLeakChecklist(_leakInput!);
88 | _updateLeakChecklist();
89 | _clearLeakInput.fire();
90 | _leakInput = null;
91 | }
92 |
93 | Future _updateLeakChecklist() async {
94 | _leakChecklist.value =
95 | (await AppSharedPreferences.leakChecklist).map((e) => LeakItem(e)).toList();
96 | }
97 |
98 | void _verifyLeakedSites() async {
99 | _foundALeakedSite = false;
100 | _updateCountryTrayIcon();
101 | final checklist = _leakChecklist.valueOrNull;
102 | if (checklist != null) {
103 | for (var item in checklist) {
104 | _checkLeakedSite(item);
105 | }
106 | }
107 | }
108 |
109 | IOClient get _client {
110 | final httpClient = HttpClient();
111 | if (_proxyServer != null) {
112 | httpClient.findProxy = (uri) {
113 | return 'PROXY $_proxyServer';
114 | };
115 | } else {
116 | httpClient.findProxy = null;
117 | }
118 | return IOClient(httpClient);
119 | }
120 |
121 | Future _checkLeakedSite(LeakItem item) async {
122 | item.status = LeakStatus.loading;
123 | _replaceLeakItemInChecklist(item);
124 | try {
125 | final url = Uri.parse(item.url);
126 | final response = await _client.get(url).timeout(const Duration(seconds: 10));
127 | if (response.statusCode == 200) {
128 | item.status = LeakStatus.passed;
129 | } else {
130 | item.status = LeakStatus.failed;
131 | }
132 | debugPrint('leak detection for $url => ${response.bodyBytes.length ~/ 1024} Kilobytes');
133 | } on Exception catch (ex) {
134 | item.status = LeakStatus.failed;
135 | _checkNetworkRefuseException(ex);
136 | }
137 | if (item.status == LeakStatus.failed) {
138 | _foundALeakedSite = true;
139 | _updateCountryTrayIcon();
140 | }
141 | _replaceLeakItemInChecklist(item);
142 | }
143 |
144 | void _replaceLeakItemInChecklist(LeakItem item) {
145 | _leakChecklist.value = _leakChecklist.value.map((e) => e.url == item.url ? item : e).toList();
146 | }
147 |
148 | void _subscribeConnectivityChange() {
149 | Connectivity().onConnectivityChanged.listen((ConnectivityResult result) async {
150 | if (result != ConnectivityResult.none) {
151 | await _checkProxySettings();
152 | _checkIpLocation();
153 | _verifyLeakedSites();
154 | _checkPing();
155 | } else {
156 | setSystemTrayStatusToOffline();
157 | }
158 | });
159 | }
160 |
161 | void _checkPing() async {
162 | _ping.value = await HttpUtils.measureHttpPing();
163 | }
164 |
165 | void _runIpCheckInfinitely() async {
166 | while (true) {
167 | await _checkProxySettings();
168 | _checkIpLocation();
169 | await Future.delayed(const Duration(seconds: 20));
170 | }
171 | }
172 |
173 | void _runKerioCheckInfinitely() async {
174 | while (true) {
175 | _checkKerioBalance();
176 | await Future.delayed(const Duration(seconds: 60));
177 | }
178 | }
179 |
180 | void _pingGoogle() async {
181 | try {
182 | _isPingingGoogle = true;
183 | final url = Uri.parse('https://google.com');
184 | await _client.get(url).timeout(const Duration(seconds: 5));
185 | } on TimeoutException {
186 | _isPingingGoogle = false;
187 | _checkNetworkConnectivity();
188 | return;
189 | } on SocketException catch (ex) {
190 | _checkNetworkRefuseException(ex);
191 | }
192 | _isPingingGoogle = false;
193 | }
194 |
195 | void _checkNetworkRefuseException(Exception ex) {
196 | if (ex is SocketException &&
197 | ex.message.startsWith('The remote computer refused the network connection.')) {
198 | _proxyServer = null;
199 | }
200 | }
201 |
202 | Future _checkIpLocation() async {
203 | http.Response response;
204 | try {
205 | final ipv4 = (await _client.get(Uri.parse("https://api.ipify.org"))).body;
206 | final uri = Uri.parse('http://ip-api.com/json/$ipv4?fields=1057497');
207 | response = await _client.get(uri).timeout(const Duration(seconds: 10));
208 | } on TimeoutException {
209 | _checkNetworkConnectivity();
210 | return;
211 | } on SocketException catch (ex) {
212 | _checkNetworkRefuseException(ex);
213 | return;
214 | } on Exception {
215 | _checkNetworkConnectivity();
216 | return;
217 | }
218 | final json = jsonDecode(response.body);
219 | if (json['lat'] != null && json['lon'] != null) {
220 | _latLng.sink.add(LatLng(json['lat'], json['lon']));
221 | }
222 | _ipLookupResult.value = json;
223 | _updateCountryTrayIcon();
224 | }
225 |
226 | Future _checkProxySettings() async {
227 | final localNetwork = await AppCmd.getLocalNetworkInfo();
228 | _localNetwork.value = localNetwork;
229 | final proxyResult = await AppCmd.getProxySettings();
230 | var shouldRefreshLeakedSites = false;
231 | if ((proxyResult.proxyEnabled && _proxyServer != proxyResult.proxyServer) ||
232 | (!proxyResult.proxyEnabled && _proxyServer != null)) {
233 | // there was a change in proxy settings
234 | shouldRefreshLeakedSites = true;
235 | }
236 | if (proxyResult.proxyEnabled) {
237 | _proxyServer = proxyResult.proxyServer;
238 | } else {
239 | _proxyServer = null;
240 | }
241 | if (shouldRefreshLeakedSites) {
242 | _verifyLeakedSites();
243 | }
244 | }
245 |
246 | void _checkKerioBalance() async {
247 | final (total, remaining) = await KerioUtils.getAccountBalance();
248 | var lowBalanceToastCount = await AppSharedPreferences.kerioLowBalanceToastCount;
249 | var lastToastDate = await AppSharedPreferences.kerioLowBalanceToastDate;
250 |
251 | final now = DateTime.now();
252 | final today = DateTime(now.year, now.month, now.day);
253 |
254 | if (lastToastDate == null || DateTime.parse(lastToastDate).isBefore(today)) {
255 | // New day, reset count
256 | lowBalanceToastCount = 0;
257 | await AppSharedPreferences.setKerioLowBalanceToastCount(0);
258 | await AppSharedPreferences.setKerioLowBalanceToastDate(today.toIso8601String());
259 | }
260 |
261 | if (remaining < 1073741824 && lowBalanceToastCount < 2) {
262 | WinToast.instance().showToast(type: ToastType.text01, title: 'Less than 1 GB is left in your kerio account!');
263 | await AppSharedPreferences.setKerioLowBalanceToastCount(lowBalanceToastCount + 1);
264 | await AppSharedPreferences.setKerioLowBalanceToastDate(today.toIso8601String());
265 | }
266 | }
267 |
268 | void _checkNetworkConnectivity() async {
269 | final result = await (Connectivity().checkConnectivity());
270 | if (result == ConnectivityResult.none) {
271 | setSystemTrayStatusToOffline();
272 | } else {
273 | setSystemTrayStatusToNetworkError();
274 | if (!_isPingingGoogle) {
275 | _pingGoogle();
276 | }
277 | }
278 | }
279 |
280 | void onConnectionTestClick() async {
281 | _downloadSpeed.value = 0;
282 | _uploadSpeed.value = 0;
283 | _speedTestStatus.value = 'Running';
284 | speedtest.getDataspeedtest(
285 | downloadOnProgress: ((percent, transferRate) {
286 | _downloadSpeed.value = transferRate;
287 | }),
288 | uploadOnProgress: ((percent, transferRate) {
289 | _uploadSpeed.value = transferRate;
290 | }),
291 | progressResponse: ((responseTime, jitter) {
292 | // nothing to do
293 | }),
294 | onError: ((errorMessage) {
295 | _downloadSpeed.value = 0;
296 | _uploadSpeed.value = 0;
297 | _speedTestStatus.value = 'Error';
298 | }),
299 | onDone: () {
300 | _speedTestStatus.value = 'Done';
301 | },
302 | );
303 | }
304 |
305 | void onExitClick() {
306 | destroySystemTray();
307 | exit(0);
308 | }
309 |
310 | void onRefreshButtonClick() async {
311 | _handleRefresh();
312 | }
313 |
314 | @override
315 | void onSystemTrayRefreshButtonClick() {
316 | _handleRefresh();
317 | }
318 |
319 | void _handleRefresh() async {
320 | await _checkProxySettings();
321 | _checkPing();
322 | _pingGoogle();
323 | _checkIpLocation();
324 | _verifyLeakedSites();
325 | }
326 |
327 | void _updateCountryTrayIcon() async {
328 | final json = _ipLookupResult.valueOrNull;
329 | if (json == null) {
330 | return;
331 | }
332 | final country = json['country'];
333 | bool isIran = country == 'Iran';
334 | var tooltip = '';
335 | if (_foundALeakedSite) {
336 | tooltip = 'IRNet: $country (Leaked!)';
337 | } else {
338 | tooltip = 'IRNet: $country';
339 | }
340 | var globIcon = 'assets/globe.ico';
341 | if (_foundALeakedSite && (await AppSharedPreferences.showLeakInSysTray)) {
342 | globIcon = 'assets/globe_leaked.ico';
343 | }
344 | final iconPath = isIran ? 'assets/iran.ico' : globIcon;
345 | updateSysTrayIcon(tooltip, iconPath);
346 | debugPrint('Country => $country');
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/lib/data/leak_item.dart:
--------------------------------------------------------------------------------
1 | class LeakItem {
2 | LeakItem(this.url, {this.status});
3 |
4 | final String url;
5 | LeakStatus? status;
6 |
7 | static List prePopulatedUrls() {
8 | return [
9 | 'https://developer.android.com',
10 | 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/4.1.3/gradle-4.1.3.pom',
11 | 'https://storage.googleapis.com/dartlang-pub-public-packages/packages/live_event-0.0.1.tar.gz'
12 | ];
13 | }
14 | }
15 |
16 | enum LeakStatus { failed, passed, loading }
17 |
--------------------------------------------------------------------------------
/lib/data/shared_preferences.dart:
--------------------------------------------------------------------------------
1 | import 'package:shared_preferences/shared_preferences.dart';
2 |
3 | class AppSharedPreferences {
4 | static Future get kerioIP async {
5 | return (await _preference).getString(_keyKerioIP);
6 | }
7 |
8 | static Future setKerioIP(String value) async {
9 | (await _preference).setString(_keyKerioIP, value);
10 | }
11 |
12 | static Future get kerioUsername async {
13 | return (await _preference).getString(_keyKerioUsername);
14 | }
15 |
16 | static Future setKerioUsername(String value) async {
17 | (await _preference).setString(_keyKerioUsername, value);
18 | }
19 |
20 | static Future get kerioPassword async {
21 | return (await _preference).getString(_keyKerioPassword);
22 | }
23 |
24 | static Future setKerioPassword(String value) async {
25 | (await _preference).setString(_keyKerioPassword, value);
26 | }
27 |
28 | static Future get kerioAutoLogin async {
29 | return (await _preference).getBool(_keyKerioAutoLogin) ?? true;
30 | }
31 |
32 | static Future setKerioAutoLogin(bool value) async {
33 | (await _preference).setBool(_keyKerioAutoLogin, value);
34 | }
35 |
36 | static Future get kerioLowBalanceToastCount async {
37 | return (await _preference).getInt(_keyKerioLowBalanceToastCount) ?? 0;
38 | }
39 |
40 | static Future setKerioLowBalanceToastCount(int value) async {
41 | (await _preference).setInt(_keyKerioLowBalanceToastCount, value);
42 | }
43 |
44 | static Future get kerioLowBalanceToastDate async {
45 | return (await _preference).getString(_keyKerioLowBalanceToastDate);
46 | }
47 |
48 | static Future setKerioLowBalanceToastDate(String value) async {
49 | (await _preference).setString(_keyKerioLowBalanceToastDate, value);
50 | }
51 |
52 | static Future get showLeakInSysTray async {
53 | return (await _preference).getBool(_keyShowLeakInSysTray) ?? true;
54 | }
55 |
56 | static Future setShowLeakInSysTray(bool value) async {
57 | (await _preference).setBool(_keyShowLeakInSysTray, value);
58 | }
59 |
60 | static Future get isLeakPrePopulated async {
61 | return (await _preference).getBool(_keyIsLeakPrePopulated) ?? false;
62 | }
63 |
64 | static Future setIsLeakPrePopulated(bool value) async {
65 | (await _preference).setBool(_keyIsLeakPrePopulated, value);
66 | }
67 |
68 | static Future> get leakChecklist async {
69 | return ((await _preference).getString(_keyLeakCheckList) ?? '').split(';');
70 | }
71 |
72 | static Future addToLeakChecklist(String value) async {
73 | var checklist = ((await _preference).getString(_keyLeakCheckList) ?? '');
74 | if (checklist == '') {
75 | checklist += value;
76 | } else {
77 | checklist += ';$value';
78 | }
79 | (await _preference).setString(_keyLeakCheckList, checklist);
80 | }
81 |
82 | static Future removeFromLeakChecklist(String value) async {
83 | final previousChecklist = await leakChecklist;
84 | previousChecklist.removeWhere((element) => element == value);
85 | (await _preference).setString(_keyLeakCheckList, previousChecklist.join(';'));
86 | }
87 |
88 | static SharedPreferences? __instance;
89 | static Future get _preference async {
90 | __instance ??= await SharedPreferences.getInstance();
91 | return __instance!;
92 | }
93 |
94 | static const _keyIsLeakPrePopulated = 'isLeakPrePopulated';
95 | static const _keyShowLeakInSysTray = 'showLeakInSysTray';
96 | static const _keyLeakCheckList = 'leakChecklist';
97 | static const _keyKerioIP = 'kerioIP';
98 | static const _keyKerioUsername = 'kerioUsername';
99 | static const _keyKerioPassword = 'kerioPassword';
100 | static const _keyKerioAutoLogin = 'kerioAutoLogin';
101 | static const _keyKerioLowBalanceToastCount = 'kerioLowBalanceToastCount';
102 | static const _keyKerioLowBalanceToastDate = 'kerioLowBalanceToastDate';
103 | }
--------------------------------------------------------------------------------
/lib/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:ir_net/views/connection.dart';
3 | import 'package:ir_net/views/ip_stat.dart';
4 | import 'package:ir_net/views/leak.dart';
5 | import 'package:ir_net/views/options.dart';
6 |
7 | import 'main.dart';
8 |
9 | class HomePage extends StatefulWidget {
10 | const HomePage({super.key});
11 |
12 | @override
13 | State createState() => _HomePageState();
14 | }
15 |
16 | class _HomePageState extends State {
17 | @override
18 | Widget build(BuildContext context) {
19 | return Scaffold(
20 | body: Center(
21 | child: SingleChildScrollView(
22 | child: Column(
23 | crossAxisAlignment: CrossAxisAlignment.center,
24 | mainAxisAlignment: MainAxisAlignment.center,
25 | children: [
26 | const Row(
27 | mainAxisAlignment: MainAxisAlignment.center,
28 | crossAxisAlignment: CrossAxisAlignment.start,
29 | children: [
30 | LeakView(),
31 | SizedBox(width: 64),
32 | IpStatView(),
33 | ],
34 | ),
35 | const SizedBox(height: 16),
36 | const Row(
37 | mainAxisAlignment: MainAxisAlignment.center,
38 | children: [
39 | AppOptions(),
40 | SizedBox(width: 64),
41 | Connection()
42 | ],
43 | ),
44 | const SizedBox(height: 24),
45 | Row(
46 | mainAxisAlignment: MainAxisAlignment.center,
47 | children: [
48 | exitButton(),
49 | const SizedBox(width: 16),
50 | refreshButton(),
51 | ],
52 | ),
53 | ],
54 | ),
55 | ),
56 | ),
57 | );
58 | }
59 |
60 | Widget exitButton() {
61 | return ElevatedButton(
62 | style: ButtonStyle(minimumSize: MaterialStateProperty.all(const Size(80, 56))),
63 | onPressed: bloc.onExitClick,
64 | child: const Text('Exit'),
65 | );
66 | }
67 |
68 | Widget refreshButton() {
69 | return ElevatedButton(
70 | style: ButtonStyle(minimumSize: MaterialStateProperty.all(const Size(80, 56))),
71 | onPressed: bloc.onRefreshButtonClick,
72 | child: const Text('Refresh'),
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:ir_net/data/leak_item.dart';
5 | import 'package:ir_net/data/shared_preferences.dart';
6 | import 'package:launch_at_startup/launch_at_startup.dart';
7 | import 'package:package_info_plus/package_info_plus.dart';
8 | import 'package:win_toast/win_toast.dart';
9 | import 'package:window_manager/window_manager.dart';
10 | import 'package:windows_single_instance/windows_single_instance.dart';
11 |
12 | import 'app.dart';
13 | import 'bloc.dart';
14 |
15 | final bloc = AppBloc();
16 |
17 | void main() async {
18 | WidgetsFlutterBinding.ensureInitialized();
19 | await initWindowManager();
20 | await initSingleInstance();
21 | await initWinToast();
22 | await initLaunchAtStartup();
23 | await initSharedPreferences();
24 | bloc.initialize();
25 | runApp(const App());
26 | }
27 |
28 | Future initWindowManager() async {
29 | await windowManager.ensureInitialized();
30 | WindowOptions windowOptions = const WindowOptions(
31 | size: Size(1000, 780),
32 | );
33 | windowManager.waitUntilReadyToShow(windowOptions, () {
34 | windowManager.setTitle("IRNet: freedom does not have a price");
35 | },);
36 | }
37 |
38 | Future initSingleInstance() async {
39 | await WindowsSingleInstance.ensureSingleInstance([], "pipeMain");
40 | }
41 |
42 | Future initWinToast() async {
43 | await WinToast.instance().initialize(
44 | appName: 'IRNet',
45 | productName: 'IRNet',
46 | companyName: 'BuildToApp',
47 | );
48 | }
49 |
50 | Future initSharedPreferences() async {
51 | if (!(await AppSharedPreferences.isLeakPrePopulated)) {
52 | for (var url in LeakItem.prePopulatedUrls()) {
53 | await AppSharedPreferences.addToLeakChecklist(url);
54 | }
55 | await AppSharedPreferences.setIsLeakPrePopulated(true);
56 | }
57 | if ((await AppSharedPreferences.kerioIP) == null) {
58 | await AppSharedPreferences.setKerioIP('172.18.18.1:4080');
59 | }
60 | }
61 |
62 | Future initLaunchAtStartup() async {
63 | PackageInfo packageInfo = await PackageInfo.fromPlatform();
64 | LaunchAtStartup.instance.setup(
65 | appName: packageInfo.appName,
66 | appPath: Platform.resolvedExecutable,
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/lib/utils/cmd.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | class AppCmd {
4 | static Future getProxySettings() async {
5 | var executable = r'reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings"';
6 | var result = await Process.run(executable, []);
7 | final stdout = result.stdout.toString();
8 | String? proxyServer;
9 | var proxyIsEnabled = false;
10 | if (stdout.isNotEmpty) {
11 | final lines = stdout.split('\r\n');
12 | for (var element in lines) {
13 | if (element.contains('ProxyEnable') && element.endsWith('0x1')) {
14 | proxyIsEnabled = true;
15 | } else if (element.contains('ProxyEnable') && element.endsWith('0x0')) {
16 | proxyIsEnabled = false;
17 | }
18 | if (element.contains('ProxyServer')) {
19 | proxyServer = element.split(' ').last;
20 | break;
21 | }
22 | }
23 | }
24 | return WinRegProxyResult(proxyIsEnabled, proxyServer);
25 | }
26 |
27 | static Future getLocalNetworkInfo() async {
28 | final arpAddresses = await _getArpAddresses();
29 | var command = await Process.run(r'ipconfig', [r'/all']);
30 | final stdout = command.stdout.toString();
31 | if (stdout.isEmpty) {
32 | throw r'Cannot resolve command ipconfig /all';
33 | }
34 | final lines = stdout.split('\r\n');
35 | final interfaces = [];
36 | var dns1 = '';
37 | var dns2 = '';
38 | var emptyLinesCount = 0;
39 | var interfaceName = '';
40 | for (var line in lines) {
41 | if (emptyLinesCount == 2) {
42 | emptyLinesCount = 0;
43 | }
44 | if (line.isEmpty) {
45 | emptyLinesCount++;
46 | }
47 | if (emptyLinesCount == 1 && line.contains(' adapter ')) {
48 | interfaceName = line.split(' adapter ')[1].replaceAll(':', '');
49 | }
50 | if (emptyLinesCount > 0) {
51 | continue;
52 | }
53 | if (line.contains(':') && line.contains('IPv4 Address')) {
54 | for (var ip in arpAddresses) {
55 | final ipPartOfLine = line.split(':')[1].trimLeft();
56 | if (interfaceName.isNotEmpty && ipPartOfLine.startsWith(ip)) {
57 | interfaces.add(NetworkInterface(interfaceName, ip));
58 | break;
59 | }
60 | }
61 | }
62 | if (dns1.isNotEmpty && dns2.isEmpty && !line.contains(':')) {
63 | dns2 = line.trimLeft();
64 | }
65 | if (dns2.isEmpty && line.contains('DNS Servers')) {
66 | dns1 = line.split(':')[1].trimLeft();
67 | }
68 | }
69 | return LocalNetworksResult(interfaces, [dns1, dns2]);
70 | }
71 |
72 | static Future> _getArpAddresses() async {
73 | final result = [];
74 | var command = await Process.run(r'arp', [r'-a']);
75 | final stdout = command.stdout.toString();
76 | if (stdout.isNotEmpty) {
77 | final lines = stdout.split('\r\n');
78 | for (var element in lines) {
79 | if (element.startsWith('Interface: ')) {
80 | result.add(element.split(' ')[1]);
81 | }
82 | }
83 | }
84 | return result;
85 | }
86 | }
87 |
88 | class LocalNetworksResult {
89 | LocalNetworksResult(this.interfaces, this.dns);
90 |
91 | final List interfaces;
92 | final List dns;
93 | }
94 |
95 | class NetworkInterface {
96 | NetworkInterface(this.interfaceName, this.ipv4);
97 |
98 | final String interfaceName;
99 | final String ipv4;
100 | }
101 |
102 | class WinRegProxyResult {
103 | WinRegProxyResult(this.proxyEnabled, this.proxyServer);
104 |
105 | final bool proxyEnabled;
106 | final String? proxyServer;
107 | }
108 |
--------------------------------------------------------------------------------
/lib/utils/http.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:dio/dio.dart';
4 |
5 | class HttpUtils {
6 | static final Dio _dio = Dio();
7 |
8 | static Future measureHttpPing({
9 | String url = "https://www.gstatic.com/generate_204",
10 | Duration timeout = const Duration(seconds: 5),
11 | }) async {
12 | _dio.options = BaseOptions(headers: {
13 | HttpHeaders.connectionHeader: 'keep-alive', // Ensure keep-alive headers
14 | });
15 | try {
16 | await _dio.get(url).timeout(timeout); // just a warm up connection to get a reliable result
17 | final firstTime = DateTime.now().millisecondsSinceEpoch;
18 | final response = await _dio.get(url).timeout(timeout);
19 | final secondTime = DateTime.now().millisecondsSinceEpoch;
20 | if (response.statusCode == 200 || response.statusCode == 204) {
21 | return (secondTime - firstTime).toDouble();
22 | } else {
23 | return 0; // server responded but with an error
24 | }
25 | } on Exception catch (_) {
26 | return 0; // timeout or unreachable
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/utils/kerio.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:http/http.dart' as http;
4 |
5 | import '../data/shared_preferences.dart';
6 |
7 | class KerioUtils {
8 | static Future<(int, int)> getAccountBalance() async {
9 | final ip = await AppSharedPreferences.kerioIP;
10 | final username = await AppSharedPreferences.kerioUsername;
11 | final password = await AppSharedPreferences.kerioPassword;
12 |
13 | // Step 1: Login and extract cookie
14 | final loginUrl = 'http://$ip/internal/dologin.php';
15 | final loginResponse = await http.post(
16 | Uri.parse(loginUrl),
17 | body: {
18 | 'kerio_username': username,
19 | 'kerio_password': password,
20 | },
21 | );
22 |
23 | final cookieHeader = loginResponse.headers['set-cookie'];
24 | if (cookieHeader == null || !cookieHeader.contains('TOKEN_CONTROL_WEBIFACE=')) {
25 | throw Exception('Login failed or TOKEN_CONTROL_WEBIFACE not found.');
26 | }
27 |
28 | final cookies = cookieHeader.split(',');
29 | final tokenCookie = cookies
30 | .map((c) => c.trim())
31 | .firstWhere(
32 | (c) => c.startsWith('TOKEN_CONTROL_WEBIFACE='),
33 | orElse: () => throw Exception('TOKEN_CONTROL_WEBIFACE not found in cookies'),
34 | );
35 |
36 | final token = tokenCookie.split('=')[1].split(';')[0];
37 |
38 | final rawCookies = cookieHeader.split(',');
39 | final cookieMap = {};
40 | for (var cookie in rawCookies) {
41 | final parts = cookie.split(';')[0].trim(); // Take only key=value part
42 | final kv = parts.split('=');
43 | if (kv.length == 2) {
44 | cookieMap[kv[0]] = kv[1];
45 | }
46 | }
47 | final cookieHeaderValue = cookieMap.entries.map((e) => '${e.key}=${e.value}').join('; ');
48 |
49 | // Step 2: Prepare headers
50 | final balanceUrl = 'http://$ip/lib/api/jsonrpc/';
51 | final headers = {
52 | 'Accept': '*/*',
53 | 'Accept-Language': 'en-US,en;q=0.9,fa;q=0.8',
54 | 'Connection': 'keep-alive',
55 | 'Content-Type': 'application/json',
56 | 'Origin': 'http://$ip',
57 | 'Referer': 'http://$ip/',
58 | 'User-Agent':
59 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36',
60 | 'X-Requested-With': 'XMLHttpRequest',
61 | 'X-Token': token,
62 | 'Cookie': cookieHeaderValue
63 | };
64 |
65 | // Step 3: Body
66 | final body = jsonEncode({
67 | "jsonrpc": "2.0",
68 | "id": 1,
69 | "method": "Batch.run",
70 | "params": {
71 | "commandList": [
72 | {"method": "MyAccount.get"},
73 | {"method": "MyAccount.getRasIntefaces"}
74 | ]
75 | }
76 | });
77 |
78 | // Step 4: Send request
79 | final balanceResponse = await http.post(
80 | Uri.parse(balanceUrl),
81 | headers: headers,
82 | body: body,
83 | );
84 |
85 | if (balanceResponse.statusCode != 200) {
86 | throw Exception('Failed to fetch balance data');
87 | }
88 |
89 | final data = jsonDecode(balanceResponse.body);
90 | final quota = data['result'][0]['result']['quota']['month'];
91 |
92 | final total = int.parse(quota['value']);
93 | final down = int.parse(quota['down']);
94 | final up = int.parse(quota['up']);
95 | final remaining = total - (down + up);
96 |
97 | return (total, remaining);
98 | }
99 |
100 | static String formatBytes(int bytes) {
101 | const kb = 1024;
102 | const mb = kb * 1024;
103 | const gb = mb * 1024;
104 |
105 | if (bytes >= gb) {
106 | return '${(bytes / gb).toStringAsFixed(2)} GB';
107 | } else if (bytes >= mb) {
108 | return '${(bytes / mb).toStringAsFixed(2)} MB';
109 | } else if (bytes >= kb) {
110 | return '${(bytes / kb).toStringAsFixed(2)} KB';
111 | } else {
112 | return '$bytes B';
113 | }
114 | }
115 | }
--------------------------------------------------------------------------------
/lib/utils/system_tray.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:system_tray/system_tray.dart';
5 |
6 | mixin AppSystemTray {
7 | final SystemTray _systemTray = SystemTray();
8 | final AppWindow _appWindow = AppWindow();
9 |
10 | void onSystemTrayRefreshButtonClick();
11 |
12 | void updateSysTrayIcon(String tooltip, String iconPath) {
13 | _systemTray.setToolTip(tooltip);
14 | _systemTray.setImage(iconPath);
15 | }
16 |
17 | void setSystemTrayStatusToOffline() {
18 | _systemTray.setImage('assets/offline.ico');
19 | _systemTray.setToolTip('IRNet: OFFLINE');
20 | }
21 |
22 | void setSystemTrayStatusToNetworkError() {
23 | _systemTray.setImage('assets/network_error.ico');
24 | _systemTray.setToolTip('IRNet: Network error');
25 | }
26 |
27 | void destroySystemTray() {
28 | _systemTray.destroy();
29 | }
30 |
31 | Future initSystemTray() async {
32 | await _systemTray.initSystemTray(
33 | title: "system tray",
34 | iconPath: 'assets/loading.ico',
35 | );
36 | final Menu menu = Menu();
37 | await menu.buildFrom([
38 | MenuItemLabel(label: 'Show', onClicked: (menuItem) => _appWindow.show()),
39 | MenuItemLabel(label: 'Hide', onClicked: (menuItem) => _appWindow.hide()),
40 | MenuItemLabel(
41 | label: 'Refresh',
42 | onClicked: (menuItem) {
43 | onSystemTrayRefreshButtonClick();
44 | },
45 | ),
46 | MenuItemLabel(
47 | label: 'Exit',
48 | onClicked: (menuItem) {
49 | _systemTray.destroy();
50 | exit(0);
51 | },
52 | ),
53 | ]);
54 |
55 | await _systemTray.setContextMenu(menu);
56 | _systemTray.registerSystemTrayEventHandler((eventName) {
57 | debugPrint("eventName: $eventName");
58 | if (eventName == kSystemTrayEventClick) {
59 | _appWindow.show();
60 | } else if (eventName == kSystemTrayEventRightClick) {
61 | _systemTray.popUpContextMenu();
62 | }
63 | });
64 |
65 | _appWindow.hide();
66 | _systemTray.setToolTip('IRNet: NOT READY');
67 | }
68 | }
--------------------------------------------------------------------------------
/lib/views/connection.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../main.dart';
4 |
5 | class Connection extends StatefulWidget {
6 | const Connection({super.key});
7 |
8 | @override
9 | State createState() => _ConnectionState();
10 | }
11 |
12 | class _ConnectionState extends State {
13 | @override
14 | Widget build(BuildContext context) {
15 | return Container(
16 | width: 400,
17 | height: 100,
18 | decoration: BoxDecoration(
19 | border: Border.all(color: Colors.blueAccent),
20 | borderRadius: BorderRadius.circular(8),
21 | ),
22 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
23 | child: Row(
24 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
25 | crossAxisAlignment: CrossAxisAlignment.center,
26 | children: [
27 | results(),
28 | const SizedBox(width: 24),
29 | testButton(),
30 | ],
31 | ),
32 | );
33 | }
34 |
35 | Widget results() {
36 | return Column(
37 | crossAxisAlignment: CrossAxisAlignment.start,
38 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
39 | children: [
40 | pingRow(),
41 | downloadRow(),
42 | uploadRow(),
43 | ],
44 | );
45 | }
46 |
47 | Widget pingRow() {
48 | return StreamBuilder(
49 | stream: bloc.ping,
50 | builder: (context, snapshot) {
51 | final value = snapshot.data ?? 0.0;
52 | return Row(
53 | crossAxisAlignment: CrossAxisAlignment.center,
54 | children: [
55 | const Icon(Icons.timer, color: Colors.teal, size: 18),
56 | const SizedBox(width: 4),
57 | Text(
58 | 'Ping: ${value.toInt()} ms',
59 | textAlign: TextAlign.center,
60 | style: const TextStyle(fontSize: 16, color: Colors.teal, fontWeight: FontWeight.bold),
61 | )
62 | ],
63 | );
64 | },
65 | );
66 | }
67 |
68 | Widget downloadRow() {
69 | return StreamBuilder(
70 | stream: bloc.downloadSpeed,
71 | builder: (context, snapshot) {
72 | final value = (snapshot.data ?? 0.0).toInt();
73 | final formattedValue = value == 0 ? '--' : '${value.toInt()} Mb/s';
74 | return Row(
75 | crossAxisAlignment: CrossAxisAlignment.end,
76 | children: [
77 | const Icon(Icons.download, color: Colors.deepOrange, size: 18),
78 | const SizedBox(width: 4),
79 | Text(
80 | 'Download speed: $formattedValue',
81 | textAlign: TextAlign.center,
82 | style: const TextStyle(
83 | fontSize: 16, color: Colors.deepOrange, fontWeight: FontWeight.bold),
84 | ),
85 | ],
86 | );
87 | },
88 | );
89 | }
90 |
91 | Widget uploadRow() {
92 | return StreamBuilder(
93 | stream: bloc.uploadSpeed,
94 | builder: (context, snapshot) {
95 | var value = (snapshot.data ?? 0.0).toInt();
96 | if (value > 500) {
97 | value = 0;
98 | }
99 | final formattedValue = value == 0 ? '--' : '${value.toInt()} Mb/s';
100 | return Row(
101 | crossAxisAlignment: CrossAxisAlignment.end,
102 | children: [
103 | const Icon(Icons.upload, color: Colors.deepPurple, size: 18),
104 | const SizedBox(width: 4),
105 | Text(
106 | 'Upload speed: $formattedValue',
107 | textAlign: TextAlign.center,
108 | style: const TextStyle(
109 | fontSize: 16, color: Colors.deepPurple, fontWeight: FontWeight.bold),
110 | ),
111 | ],
112 | );
113 | },
114 | );
115 | }
116 |
117 | Widget testButton() {
118 | return StreamBuilder(stream: bloc.speedTestStatus, builder: (context, snapshot) {
119 | final value = snapshot.data ?? 'Not started';
120 |
121 | return Column(
122 | mainAxisAlignment: MainAxisAlignment.center,
123 | children: [
124 | ElevatedButton(
125 | onPressed: () {
126 | if (value != 'Running') {
127 | bloc.onConnectionTestClick();
128 | }
129 | },
130 | style: ElevatedButton.styleFrom(
131 | shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8))),
132 | padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
133 | backgroundColor: value == 'Running' ? Colors.grey : Colors.blue,
134 | ),
135 | child: const Text('Test', style: TextStyle(color: Colors.white, fontSize: 18)),
136 | ),
137 | const SizedBox(height: 8),
138 | if (value == 'Running')
139 | const SizedBox(width: 20, height: 20, child: CircularProgressIndicator())
140 | else
141 | Text(value)
142 | ],
143 | );
144 | });
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/lib/views/ip_stat.dart:
--------------------------------------------------------------------------------
1 | import 'dart:collection';
2 | import 'dart:math';
3 |
4 | import 'package:cached_network_image/cached_network_image.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:ir_net/main.dart';
7 | import 'package:ir_net/utils/cmd.dart';
8 | import 'package:latlng/latlng.dart';
9 | import 'package:map/map.dart';
10 |
11 | class IpStatView extends StatefulWidget {
12 | const IpStatView({super.key});
13 |
14 | @override
15 | State createState() => _IpStatViewState();
16 | }
17 |
18 | class _IpStatViewState extends State {
19 | late MapController controller;
20 |
21 | @override
22 | void initState() {
23 | controller = MapController(
24 | location: const LatLng(35.69439, 51.42151),
25 | zoom: 8,
26 | );
27 | bloc.latLng.listen((latLng) {
28 | setState(() {
29 | controller.center = latLng;
30 | });
31 | });
32 | super.initState();
33 | }
34 |
35 | @override
36 | Widget build(BuildContext context) {
37 | return Column(
38 | crossAxisAlignment: CrossAxisAlignment.center,
39 | mainAxisAlignment: MainAxisAlignment.center,
40 | children: [
41 | locationTag(),
42 | const SizedBox(height: 16),
43 | map(),
44 | const SizedBox(height: 16),
45 | networkInfo(),
46 | const SizedBox(height: 16),
47 | lookupResult(),
48 | ],
49 | );
50 | }
51 |
52 | Widget networkInfo() {
53 | return StreamBuilder(
54 | stream: bloc.localNetwork,
55 | builder: (context, snapshot) {
56 | final data = snapshot.data;
57 | if (data == null) {
58 | return const SizedBox.shrink();
59 | }
60 | return SizedBox(
61 | width: 400,
62 | child: Column(
63 | children: [
64 | ipAddress(),
65 | coloredText('DNS records: ${data.dns[0]}, ${data.dns[1]}'),
66 | coloredText('Local IP Address: ${_localIpText(data.interfaces)}')
67 | ],
68 | ),
69 | );
70 | },
71 | );
72 | }
73 |
74 | String _localIpText(List interfaces) {
75 | var result = '';
76 | for (var i = 0; i < interfaces.length; i++) {
77 | final inf = interfaces[i];
78 | if (interfaces.length > 1 && i > 0 && i < interfaces.length) {
79 | result += '\n ';
80 | }
81 | var interfaceName = inf.interfaceName;
82 | if (interfaceName.length > 10) {
83 | interfaceName = interfaceName.substring(0, 5) + "..." + interfaceName.substring(interfaceName.length - 5);
84 | }
85 | result += '${inf.ipv4} ($interfaceName)';
86 | }
87 | return result;
88 | }
89 |
90 | Widget ipAddress() {
91 | return StreamBuilder(
92 | stream: bloc.ipLookupResult,
93 | builder: (context, snapshot) {
94 | final data = snapshot.data;
95 | if (data == null) {
96 | return const SizedBox.shrink();
97 | }
98 | return coloredText('Public IP address: ${data['query']}');
99 | },
100 | );
101 | }
102 |
103 | Widget coloredText(String value) {
104 | return Container(
105 | color: Colors.black12,
106 | width: double.infinity,
107 | padding: const EdgeInsets.all(8),
108 | child: Text(value),
109 | );
110 | }
111 |
112 | Widget lookupResult() {
113 | return StreamBuilder(
114 | stream: bloc.ipLookupResult,
115 | builder: (context, snapshot) {
116 | final data = snapshot.data;
117 | if (data == null) {
118 | return const SizedBox.shrink();
119 | }
120 | var result = '';
121 | var longestLength = 1;
122 | for (MapEntry e in (data as LinkedHashMap).entries) {
123 | final len = e.key.toString().length;
124 | if (len > longestLength) {
125 | longestLength = len;
126 | }
127 | }
128 | for (MapEntry e in (data).entries) {
129 | if (e.key == 'lat' || e.key == 'lon' || e.key == 'query' || e.key == 'continent') {
130 | continue;
131 | }
132 | final charCode = '.'.codeUnitAt(0);
133 | final dots = String.fromCharCodes(
134 | List.generate(longestLength - e.key.toString().length, (index) => charCode),
135 | );
136 | result += '${e.key} $dots................. ${e.value}\n';
137 | }
138 | return Text(result);
139 | },
140 | );
141 | }
142 |
143 | Widget locationTag() {
144 | return StreamBuilder(
145 | stream: bloc.ipLookupResult,
146 | builder: (context, snapshot) {
147 | final data = snapshot.data;
148 | if (data == null) {
149 | return const Text('No data');
150 | }
151 | return Text('${data['country']}, ${data['city']}');
152 | },
153 | );
154 | }
155 |
156 | Widget map() {
157 | return Stack(
158 | alignment: Alignment.center,
159 | children: [
160 | SizedBox(
161 | width: 400,
162 | height: 150,
163 | child: mapLayout(),
164 | ),
165 | ],
166 | );
167 | }
168 |
169 | Widget mapLayout() {
170 | return MapLayout(
171 | controller: controller,
172 | builder: (context, transformer) {
173 | return TileLayer(
174 | builder: (context, x, y, z) {
175 | final tilesInZoom = pow(2.0, z).floor();
176 | while (x < 0) {
177 | x += tilesInZoom;
178 | }
179 | while (y < 0) {
180 | y += tilesInZoom;
181 | }
182 | x %= tilesInZoom;
183 | y %= tilesInZoom;
184 | final url = 'https://a.tile.openstreetmap.fr/hot/$z/$x/$y.png';
185 |
186 | return CachedNetworkImage(
187 | imageUrl: url,
188 | fit: BoxFit.cover,
189 | );
190 | },
191 | );
192 | },
193 | );
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/lib/views/kerio_login.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:http/http.dart' as http;
3 | import 'package:ir_net/data/shared_preferences.dart';
4 | import 'package:ir_net/utils/kerio.dart';
5 | import 'package:url_launcher/url_launcher.dart';
6 |
7 | class KerioLoginView extends StatefulWidget {
8 | const KerioLoginView({super.key});
9 |
10 | @override
11 | State createState() => _KerioLoginViewState();
12 | }
13 |
14 | class _KerioLoginViewState extends State {
15 | final TextEditingController _ipController = TextEditingController();
16 | final TextEditingController _usernameController = TextEditingController();
17 | final TextEditingController _passwordController = TextEditingController();
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | _attemptAutoLogin();
23 | }
24 |
25 | Future _attemptAutoLogin() async {
26 | final ip = await AppSharedPreferences.kerioIP;
27 | final username = await AppSharedPreferences.kerioUsername;
28 | final password = await AppSharedPreferences.kerioPassword;
29 | final enabled = await AppSharedPreferences.kerioAutoLogin;
30 |
31 | _ipController.text = ip ?? '';
32 | if (ip != null && username != null && password != null && enabled == true) {
33 | _ipController.text = ip;
34 | _usernameController.text = username;
35 | _passwordController.text = password;
36 | _login(true);
37 | }
38 | }
39 |
40 | void _login(bool auto) async {
41 | final ip = _ipController.text;
42 | final username = _usernameController.text;
43 | final password = _passwordController.text;
44 |
45 | if (ip.isEmpty || username.isEmpty || password.isEmpty) {
46 | _showMessage('Please fill in all fields');
47 | return;
48 | }
49 |
50 | // Save credentials for auto-login
51 | await AppSharedPreferences.setKerioIP(ip);
52 | await AppSharedPreferences.setKerioUsername(username);
53 | await AppSharedPreferences.setKerioPassword(password);
54 |
55 | final url = 'http://$ip/internal/dologin.php';
56 | final response = await http.post(
57 | Uri.parse(url),
58 | body: {
59 | 'kerio_username': username,
60 | 'kerio_password': password,
61 | },
62 | );
63 |
64 | if (auto) {
65 | return;
66 | }
67 |
68 | _showMessage('Login request sent'); // todo: handle failure case
69 | }
70 |
71 | void _showMessage(String message) {
72 | showDialog(
73 | context: context,
74 | builder: (context) => AlertDialog(
75 | content: Text(message),
76 | actions: [
77 | TextButton(
78 | onPressed: () => Navigator.of(context).pop(),
79 | child: const Text('OK'),
80 | ),
81 | ],
82 | ),
83 | );
84 | }
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | return SizedBox(
89 | width: 400,
90 | child: Column(
91 | crossAxisAlignment: CrossAxisAlignment.center,
92 | children: [
93 | ipAndBalanceRow(),
94 | const SizedBox(height: 4),
95 | credentialsRow(),
96 | const SizedBox(height: 8),
97 | loginRow()
98 | ],
99 | ),
100 | );
101 | }
102 |
103 | Widget ipAndBalanceRow() {
104 | return Row(
105 | children: [
106 | Expanded(
107 | child: ipInput(),
108 | ),
109 | const SizedBox(width: 4),
110 | Expanded(
111 | child: balance(),
112 | ),
113 | ],
114 | );
115 | }
116 |
117 | Widget balance() {
118 | return FutureBuilder(
119 | future: KerioUtils.getAccountBalance(),
120 | builder: (context, snapshot) {
121 | var (total, remaining) = snapshot.data ?? (0, 0);
122 | var totalFormatted = total == 0 ? '--' : KerioUtils.formatBytes(total);
123 | var remainingFormatted = remaining == 0 ? '--' : KerioUtils.formatBytes(remaining);
124 | return Container(
125 | padding: const EdgeInsets.only(left: 16),
126 | child: Column(
127 | crossAxisAlignment: CrossAxisAlignment.start,
128 | children: [
129 | Text(
130 | 'Remaining = $remainingFormatted',
131 | style: TextStyle(color: remaining < 1073741824 ? Colors.red : Colors.black),
132 | ),
133 | Text('Total = $totalFormatted'),
134 | ],
135 | ),
136 | );
137 | },
138 | );
139 | }
140 |
141 | Widget ipInput() {
142 | return TextField(
143 | controller: _ipController,
144 | decoration: InputDecoration(
145 | focusedBorder: const OutlineInputBorder(
146 | borderSide: BorderSide(color: Colors.green),
147 | ),
148 | enabledBorder: const OutlineInputBorder(
149 | borderSide: BorderSide(color: Colors.blue),
150 | ),
151 | hintText: 'Kerio login page IP',
152 | hintStyle: const TextStyle(color: Colors.black38),
153 | suffixIcon: IconButton(
154 | onPressed: () {
155 | final url = _ipController.text.trim();
156 | if (url.isNotEmpty) {
157 | final uri = Uri.tryParse(url.startsWith('http') ? url : 'http://$url');
158 | if (uri != null) {
159 | launchUrl(uri);
160 | }
161 | }
162 | },
163 | icon: Image.asset('assets/kerio.png', width: 24, height: 24),
164 | ),
165 | ),
166 | keyboardType: TextInputType.url,
167 | );
168 | }
169 |
170 | Widget credentialsRow() {
171 | return Row(
172 | children: [
173 | Expanded(
174 | child: username(),
175 | ),
176 | const SizedBox(width: 4),
177 | Expanded(
178 | child: password(),
179 | ),
180 | ],
181 | );
182 | }
183 |
184 | Widget username() {
185 | return TextField(
186 | controller: _usernameController,
187 | decoration: const InputDecoration(
188 | focusedBorder: OutlineInputBorder(
189 | borderSide: BorderSide(color: Colors.green),
190 | ),
191 | enabledBorder: OutlineInputBorder(
192 | borderSide: BorderSide(color: Colors.blue),
193 | ),
194 | hintText: 'Username',
195 | hintStyle: TextStyle(color: Colors.black38),
196 | ),
197 | );
198 | }
199 |
200 | Widget password() {
201 | return TextField(
202 | controller: _passwordController,
203 | decoration: const InputDecoration(
204 | focusedBorder: OutlineInputBorder(
205 | borderSide: BorderSide(color: Colors.green),
206 | ),
207 | enabledBorder: OutlineInputBorder(
208 | borderSide: BorderSide(color: Colors.blue),
209 | ),
210 | hintText: 'Password',
211 | hintStyle: TextStyle(color: Colors.black38),
212 | ),
213 | obscureText: true,
214 | );
215 | }
216 |
217 | Widget loginRow() {
218 | return Row(
219 | children: [
220 | Expanded(
221 | flex: 2,
222 | child: ElevatedButton(
223 | onPressed: () => _login(false),
224 | style: ElevatedButton.styleFrom(
225 | shape: const RoundedRectangleBorder(
226 | borderRadius: BorderRadius.all(Radius.circular(8)),
227 | ),
228 | padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
229 | backgroundColor: Colors.blue,
230 | ),
231 | child: const Text('Login', style: TextStyle(color: Colors.white)),
232 | ),
233 | ),
234 | const SizedBox(width: 10),
235 | Expanded(
236 | child: autoLoginOption(),
237 | )
238 | ],
239 | );
240 | }
241 |
242 | Widget autoLoginOption() {
243 | return FutureBuilder(
244 | future: AppSharedPreferences.kerioAutoLogin,
245 | builder: (context, snapshot) {
246 | final value = snapshot.data ?? false;
247 | return CheckboxListTile(
248 | title: const Text('Auto?'),
249 | value: value,
250 | onChanged: (enabled) async {
251 | await AppSharedPreferences.setKerioAutoLogin(enabled ?? false);
252 | setState(() {});
253 | },
254 | );
255 | },
256 | );
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/lib/views/leak.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:ir_net/data/leak_item.dart';
3 | import 'package:ir_net/main.dart';
4 | import 'package:ir_net/views/kerio_login.dart';
5 | import 'package:touch_mouse_behavior/touch_mouse_behavior.dart';
6 | import 'package:url_launcher/url_launcher.dart';
7 |
8 | class LeakView extends StatefulWidget {
9 | const LeakView({super.key});
10 |
11 | @override
12 | State createState() => _LeakViewState();
13 | }
14 |
15 | class _LeakViewState extends State {
16 | late TextEditingController textInputController;
17 |
18 | @override
19 | void initState() {
20 | textInputController = TextEditingController();
21 | bloc.clearLeakInput.listen((_) {
22 | textInputController.clear();
23 | });
24 | super.initState();
25 | }
26 |
27 | @override
28 | void dispose() {
29 | textInputController.dispose();
30 | super.dispose();
31 | }
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | return Column(
36 | children: [
37 | const Text('Leak detection'),
38 | const SizedBox(height: 16),
39 | SizedBox(
40 | width: 400,
41 | child: input(),
42 | ),
43 | const SizedBox(height: 16),
44 | items(),
45 | const KerioLoginView()
46 | ],
47 | );
48 | }
49 |
50 | Widget items() {
51 | return StreamBuilder>(
52 | stream: bloc.leakChecklist,
53 | builder: (context, snapshot) {
54 | final data = snapshot.data;
55 | if (data == null) {
56 | return const SizedBox.shrink();
57 | }
58 | return SizedBox(
59 | width: 400,
60 | height: 250,
61 | child: TouchMouseScrollable(
62 | child: ListView.builder(
63 | itemCount: data.length,
64 | itemBuilder: (context, index) {
65 | return item(data[index]);
66 | },
67 | ),
68 | ),
69 | );
70 | },
71 | );
72 | }
73 |
74 | Widget item(LeakItem item) {
75 | return InkWell(
76 | onTap: () {
77 | launchUrl(Uri.parse(item.url));
78 | },
79 | child: Container(
80 | width: 400,
81 | decoration: const BoxDecoration(
82 | shape: BoxShape.rectangle,
83 | color: Colors.black12,
84 | borderRadius: BorderRadius.all(Radius.circular(4)),
85 | ),
86 | padding: const EdgeInsets.all(8),
87 | margin: const EdgeInsets.symmetric(vertical: 4),
88 | child: Row(
89 | children: [
90 | if (item.status == LeakStatus.failed)
91 | const Icon(Icons.remove_circle_outline, color: Colors.red),
92 | if (item.status == LeakStatus.passed) const Icon(Icons.check, color: Colors.green),
93 | if (item.status == LeakStatus.loading)
94 | const SizedBox(
95 | width: 24,
96 | height: 24,
97 | child: CircularProgressIndicator(),
98 | ),
99 | const SizedBox(width: 8),
100 | Expanded(
101 | child: Text(
102 | item.url,
103 | style: const TextStyle(color: Colors.blueAccent),
104 | )),
105 | IconButton(
106 | onPressed: () => bloc.onDeleteLeakItemClick(item),
107 | icon: Icon(
108 | Icons.highlight_remove_outlined,
109 | color: Colors.red.withAlpha(80),
110 | ),
111 | )
112 | ],
113 | ),
114 | ),
115 | );
116 | }
117 |
118 | Widget input() {
119 | return TextField(
120 | controller: textInputController,
121 | onChanged: bloc.onLeakInputChanged,
122 | onSubmitted: (_) => bloc.onAddLeakItemClick(),
123 | decoration: InputDecoration(
124 | focusedBorder: const OutlineInputBorder(
125 | borderSide: BorderSide(color: Colors.green),
126 | ),
127 | enabledBorder: const OutlineInputBorder(
128 | borderSide: BorderSide(color: Colors.blue),
129 | ),
130 | hintText: 'https://developer.google.com',
131 | hintStyle: const TextStyle(color: Colors.black38),
132 | suffixIcon: IconButton(onPressed: bloc.onAddLeakItemClick, icon: const Icon(Icons.add)),
133 | ),
134 | );
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/lib/views/options.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:launch_at_startup/launch_at_startup.dart';
3 |
4 | import '../data/shared_preferences.dart';
5 |
6 | class AppOptions extends StatefulWidget {
7 | const AppOptions({super.key});
8 |
9 | @override
10 | State createState() => _AppOptionsState();
11 | }
12 |
13 | class _AppOptionsState extends State {
14 | @override
15 | Widget build(BuildContext context) {
16 | return SizedBox(
17 | width: 400,
18 | child: Column(
19 | crossAxisAlignment: CrossAxisAlignment.start,
20 | children: [
21 | showLeakInSysTray(),
22 | launchAtStartup()
23 | ],
24 | ),
25 | );
26 | }
27 |
28 | Widget launchAtStartup() {
29 | return FutureBuilder(
30 | future: LaunchAtStartup.instance.isEnabled(),
31 | builder: (context, snapshot) {
32 | final value = snapshot.data ?? false;
33 | return CheckboxListTile(
34 | title: const Text('Launch on windows startup?'),
35 | value: value,
36 | onChanged: (enabled) {
37 | if (enabled == true) {
38 | LaunchAtStartup.instance.enable();
39 | } else {
40 | LaunchAtStartup.instance.disable();
41 | }
42 | setState(() {});
43 | },
44 | );
45 | },
46 | );
47 | }
48 |
49 | Widget showLeakInSysTray() {
50 | return FutureBuilder(
51 | future: AppSharedPreferences.showLeakInSysTray,
52 | builder: (context, snapshot) {
53 | final value = snapshot.data ?? false;
54 | return CheckboxListTile(
55 | title: const Text('Show leak detection on system tray icon?'),
56 | value: value,
57 | onChanged: (enabled) async {
58 | await AppSharedPreferences.setShowLeakInSysTray(enabled ?? false);
59 | setState(() {});
60 | },
61 | );
62 | },
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/linux/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Project-level configuration.
2 | cmake_minimum_required(VERSION 3.10)
3 | project(runner LANGUAGES CXX)
4 |
5 | # The name of the executable created for the application. Change this to change
6 | # the on-disk name of your application.
7 | set(BINARY_NAME "ir_net")
8 | # The unique GTK application identifier for this application. See:
9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID
10 | set(APPLICATION_ID "com.example.ir_net")
11 |
12 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13 | # versions of CMake.
14 | cmake_policy(SET CMP0063 NEW)
15 |
16 | # Load bundled libraries from the lib/ directory relative to the binary.
17 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18 |
19 | # Root filesystem for cross-building.
20 | if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21 | set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27 | endif()
28 |
29 | # Define build configuration options.
30 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31 | set(CMAKE_BUILD_TYPE "Debug" CACHE
32 | STRING "Flutter build mode" FORCE)
33 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34 | "Debug" "Profile" "Release")
35 | endif()
36 |
37 | # Compilation settings that should be applied to most targets.
38 | #
39 | # Be cautious about adding new options here, as plugins use this function by
40 | # default. In most cases, you should add new options to specific targets instead
41 | # of modifying this function.
42 | function(APPLY_STANDARD_SETTINGS TARGET)
43 | target_compile_features(${TARGET} PUBLIC cxx_std_14)
44 | target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>")
46 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>")
47 | endfunction()
48 |
49 | # Flutter library and tool build rules.
50 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51 | add_subdirectory(${FLUTTER_MANAGED_DIR})
52 |
53 | # System-level dependencies.
54 | find_package(PkgConfig REQUIRED)
55 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56 |
57 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
58 |
59 | # Define the application target. To change its name, change BINARY_NAME above,
60 | # not the value here, or `flutter run` will no longer work.
61 | #
62 | # Any new source files that you add to the application should be added here.
63 | add_executable(${BINARY_NAME}
64 | "main.cc"
65 | "my_application.cc"
66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
67 | )
68 |
69 | # Apply the standard set of build settings. This can be removed for applications
70 | # that need different build settings.
71 | apply_standard_settings(${BINARY_NAME})
72 |
73 | # Add dependency libraries. Add any application-specific dependencies here.
74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter)
75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
76 |
77 | # Run the Flutter tool portions of the build. This must not be removed.
78 | add_dependencies(${BINARY_NAME} flutter_assemble)
79 |
80 | # Only the install-generated bundle's copy of the executable will launch
81 | # correctly, since the resources must in the right relative locations. To avoid
82 | # people trying to run the unbundled copy, put it in a subdirectory instead of
83 | # the default top-level location.
84 | set_target_properties(${BINARY_NAME}
85 | PROPERTIES
86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
87 | )
88 |
89 | # Generated plugin build rules, which manage building the plugins and adding
90 | # them to the application.
91 | include(flutter/generated_plugins.cmake)
92 |
93 |
94 | # === Installation ===
95 | # By default, "installing" just makes a relocatable bundle in the build
96 | # directory.
97 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
98 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
99 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
100 | endif()
101 |
102 | # Start with a clean build bundle directory every time.
103 | install(CODE "
104 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
105 | " COMPONENT Runtime)
106 |
107 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
108 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
109 |
110 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
111 | COMPONENT Runtime)
112 |
113 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
114 | COMPONENT Runtime)
115 |
116 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
117 | COMPONENT Runtime)
118 |
119 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
120 | install(FILES "${bundled_library}"
121 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
122 | COMPONENT Runtime)
123 | endforeach(bundled_library)
124 |
125 | # Fully re-copy the assets directory on each build to avoid having stale files
126 | # from a previous install.
127 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
128 | install(CODE "
129 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
130 | " COMPONENT Runtime)
131 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
132 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
133 |
134 | # Install the AOT library on non-Debug builds only.
135 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
136 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
137 | COMPONENT Runtime)
138 | endif()
139 |
--------------------------------------------------------------------------------
/linux/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.10)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 |
12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13 | # which isn't available in 3.10.
14 | function(list_prepend LIST_NAME PREFIX)
15 | set(NEW_LIST "")
16 | foreach(element ${${LIST_NAME}})
17 | list(APPEND NEW_LIST "${PREFIX}${element}")
18 | endforeach(element)
19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20 | endfunction()
21 |
22 | # === Flutter Library ===
23 | # System-level dependencies.
24 | find_package(PkgConfig REQUIRED)
25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28 |
29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30 |
31 | # Published to parent scope for install step.
32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36 |
37 | list(APPEND FLUTTER_LIBRARY_HEADERS
38 | "fl_basic_message_channel.h"
39 | "fl_binary_codec.h"
40 | "fl_binary_messenger.h"
41 | "fl_dart_project.h"
42 | "fl_engine.h"
43 | "fl_json_message_codec.h"
44 | "fl_json_method_codec.h"
45 | "fl_message_codec.h"
46 | "fl_method_call.h"
47 | "fl_method_channel.h"
48 | "fl_method_codec.h"
49 | "fl_method_response.h"
50 | "fl_plugin_registrar.h"
51 | "fl_plugin_registry.h"
52 | "fl_standard_message_codec.h"
53 | "fl_standard_method_codec.h"
54 | "fl_string_codec.h"
55 | "fl_value.h"
56 | "fl_view.h"
57 | "flutter_linux.h"
58 | )
59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60 | add_library(flutter INTERFACE)
61 | target_include_directories(flutter INTERFACE
62 | "${EPHEMERAL_DIR}"
63 | )
64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65 | target_link_libraries(flutter INTERFACE
66 | PkgConfig::GTK
67 | PkgConfig::GLIB
68 | PkgConfig::GIO
69 | )
70 | add_dependencies(flutter flutter_assemble)
71 |
72 | # === Flutter tool backend ===
73 | # _phony_ is a non-existent file to force this command to run every time,
74 | # since currently there's no way to get a full input/output list from the
75 | # flutter tool.
76 | add_custom_command(
77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79 | COMMAND ${CMAKE_COMMAND} -E env
80 | ${FLUTTER_TOOL_ENVIRONMENT}
81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83 | VERBATIM
84 | )
85 | add_custom_target(flutter_assemble DEPENDS
86 | "${FLUTTER_LIBRARY}"
87 | ${FLUTTER_LIBRARY_HEADERS}
88 | )
89 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void fl_register_plugins(FlPluginRegistry* registry) {
15 | g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
16 | fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
17 | screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
18 | g_autoptr(FlPluginRegistrar) system_tray_registrar =
19 | fl_plugin_registry_get_registrar_for_plugin(registry, "SystemTrayPlugin");
20 | system_tray_plugin_register_with_registrar(system_tray_registrar);
21 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
22 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
23 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
24 | g_autoptr(FlPluginRegistrar) window_manager_registrar =
25 | fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
26 | window_manager_plugin_register_with_registrar(window_manager_registrar);
27 | }
28 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | screen_retriever
7 | system_tray
8 | url_launcher_linux
9 | window_manager
10 | )
11 |
12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 | )
14 |
15 | set(PLUGIN_BUNDLED_LIBRARIES)
16 |
17 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
22 | endforeach(plugin)
23 |
24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
27 | endforeach(ffi_plugin)
28 |
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/linux/my_application.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | #include
4 | #ifdef GDK_WINDOWING_X11
5 | #include
6 | #endif
7 |
8 | #include "flutter/generated_plugin_registrant.h"
9 |
10 | struct _MyApplication {
11 | GtkApplication parent_instance;
12 | char** dart_entrypoint_arguments;
13 | };
14 |
15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 |
17 | // Implements GApplication::activate.
18 | static void my_application_activate(GApplication* application) {
19 | MyApplication* self = MY_APPLICATION(application);
20 | GtkWindow* window =
21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 |
23 | // Use a header bar when running in GNOME as this is the common style used
24 | // by applications and is the setup most users will be using (e.g. Ubuntu
25 | // desktop).
26 | // If running on X and not using GNOME then just use a traditional title bar
27 | // in case the window manager does more exotic layout, e.g. tiling.
28 | // If running on Wayland assume the header bar will work (may need changing
29 | // if future cases occur).
30 | gboolean use_header_bar = TRUE;
31 | #ifdef GDK_WINDOWING_X11
32 | GdkScreen* screen = gtk_window_get_screen(window);
33 | if (GDK_IS_X11_SCREEN(screen)) {
34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 | use_header_bar = FALSE;
37 | }
38 | }
39 | #endif
40 | if (use_header_bar) {
41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 | gtk_widget_show(GTK_WIDGET(header_bar));
43 | gtk_header_bar_set_title(header_bar, "ir_net");
44 | gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 | } else {
47 | gtk_window_set_title(window, "ir_net");
48 | }
49 |
50 | gtk_window_set_default_size(window, 1280, 720);
51 | gtk_widget_show(GTK_WIDGET(window));
52 |
53 | g_autoptr(FlDartProject) project = fl_dart_project_new();
54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
55 |
56 | FlView* view = fl_view_new(project);
57 | gtk_widget_show(GTK_WIDGET(view));
58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
59 |
60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view));
61 |
62 | gtk_widget_grab_focus(GTK_WIDGET(view));
63 | }
64 |
65 | // Implements GApplication::local_command_line.
66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
67 | MyApplication* self = MY_APPLICATION(application);
68 | // Strip out the first argument as it is the binary name.
69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
70 |
71 | g_autoptr(GError) error = nullptr;
72 | if (!g_application_register(application, nullptr, &error)) {
73 | g_warning("Failed to register: %s", error->message);
74 | *exit_status = 1;
75 | return TRUE;
76 | }
77 |
78 | g_application_activate(application);
79 | *exit_status = 0;
80 |
81 | return TRUE;
82 | }
83 |
84 | // Implements GObject::dispose.
85 | static void my_application_dispose(GObject* object) {
86 | MyApplication* self = MY_APPLICATION(object);
87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
89 | }
90 |
91 | static void my_application_class_init(MyApplicationClass* klass) {
92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate;
93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
95 | }
96 |
97 | static void my_application_init(MyApplication* self) {}
98 |
99 | MyApplication* my_application_new() {
100 | return MY_APPLICATION(g_object_new(my_application_get_type(),
101 | "application-id", APPLICATION_ID,
102 | "flags", G_APPLICATION_NON_UNIQUE,
103 | nullptr));
104 | }
105 |
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "ephemeral/Flutter-Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "ephemeral/Flutter-Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import connectivity_plus
9 | import launch_at_startup
10 | import package_info_plus
11 | import path_provider_foundation
12 | import screen_retriever
13 | import shared_preferences_foundation
14 | import sqflite
15 | import system_tray
16 | import url_launcher_macos
17 | import window_manager
18 |
19 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
20 | ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
21 | LaunchAtStartupPlugin.register(with: registry.registrar(forPlugin: "LaunchAtStartupPlugin"))
22 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
23 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
24 | ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
25 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
26 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
27 | SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin"))
28 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
29 | WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
30 | }
31 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @NSApplicationMain
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "app_icon_16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "app_icon_32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "app_icon_32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "app_icon_64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "app_icon_128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "app_icon_256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "app_icon_256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "app_icon_512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "app_icon_512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "app_icon_1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = ir_net
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.irNet
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved.
15 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController.init()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: ir_net
2 | description: Windows tool to show if user is connected to Iran internet or a VPN
3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
4 | version: 1.2.2+5
5 | environment:
6 | sdk: ">=3.2.3 <4.0.0"
7 | flutter: "3.29.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 | system_tray: ^2.0.1
13 | http: ^1.1.2
14 | connectivity_plus: ^5.0.2
15 | map: ^1.3.3
16 | latlng: ^0.2.0
17 | cached_network_image: ^3.2.1
18 | rxdart: ^0.27.5
19 | launch_at_startup: ^0.0.1
20 | package_info_plus: ^4.2.0
21 | touch_mouse_behavior: ^1.0.0
22 | url_launcher: ^6.1.5
23 | shared_preferences: ^2.0.15
24 | live_event: ^1.0.0
25 | win_toast: ^0.0.2
26 | windows_single_instance: ^1.0.1
27 | dio: ^4.0.6
28 | window_manager: ^0.3.9
29 | flutter_speedtest: ^0.2.0
30 |
31 | dev_dependencies:
32 | flutter_test:
33 | sdk: flutter
34 | flutter_lints: ^2.0.0
35 | msix: ^3.6.3
36 | win32: ^5.11.0
37 |
38 | msix_config:
39 | display_name: IRNet
40 | certificate_path: C:\Workspace\Flutter\ir_net\signing\CERTIFICATE.pfx
41 | certificate_password: IrNetProject
42 | logo_path: C:\Workspace\Flutter\ir_net\assets\app_icon.png
43 | start_menu_icon_path: C:\Workspace\Flutter\ir_net\assets\app_icon.png
44 | tile_icon_path: C:\Workspace\Flutter\ir_net\assets\app_icon.png
45 | publisher_display_name: BuildToApp
46 | identity_name: com.buildtoapp.irnet
47 | msix_version: 1.0.0.0
48 | capabilities: internetClient
49 | install_certificate: true
50 | app_installer:
51 | publish_folder_path: build\windows\runner\Release
52 |
53 | flutter:
54 | uses-material-design: true
55 | assets:
56 | - assets/
57 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/screenshot.png
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility in the flutter_test package. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:ir_net/main.dart';
12 |
13 | void main() {
14 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // // Build our app and trigger a frame.
16 | // await tester.pumpWidget(const MyApp());
17 | //
18 | // // Verify that our counter starts at 0.
19 | // expect(find.text('0'), findsOneWidget);
20 | // expect(find.text('1'), findsNothing);
21 | //
22 | // // Tap the '+' icon and trigger a frame.
23 | // await tester.tap(find.byIcon(Icons.add));
24 | // await tester.pump();
25 | //
26 | // // Verify that our counter has incremented.
27 | // expect(find.text('0'), findsNothing);
28 | // expect(find.text('1'), findsOneWidget);
29 | // });
30 | }
31 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ir_net
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ir_net",
3 | "short_name": "ir_net",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Project-level configuration.
2 | cmake_minimum_required(VERSION 3.14)
3 | project(ir_net LANGUAGES CXX)
4 |
5 | # The name of the executable created for the application. Change this to change
6 | # the on-disk name of your application.
7 | set(BINARY_NAME "ir_net")
8 |
9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
10 | # versions of CMake.
11 | cmake_policy(SET CMP0063 NEW)
12 |
13 | # Define build configuration option.
14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
15 | if(IS_MULTICONFIG)
16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
17 | CACHE STRING "" FORCE)
18 | else()
19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
20 | set(CMAKE_BUILD_TYPE "Debug" CACHE
21 | STRING "Flutter build mode" FORCE)
22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
23 | "Debug" "Profile" "Release")
24 | endif()
25 | endif()
26 | # Define settings for the Profile build mode.
27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
31 |
32 | # Use Unicode for all projects.
33 | add_definitions(-DUNICODE -D_UNICODE)
34 |
35 | # Compilation settings that should be applied to most targets.
36 | #
37 | # Be cautious about adding new options here, as plugins use this function by
38 | # default. In most cases, you should add new options to specific targets instead
39 | # of modifying this function.
40 | function(APPLY_STANDARD_SETTINGS TARGET)
41 | target_compile_features(${TARGET} PUBLIC cxx_std_17)
42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
43 | target_compile_options(${TARGET} PRIVATE /EHsc)
44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
46 | endfunction()
47 |
48 | # Flutter library and tool build rules.
49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
50 | add_subdirectory(${FLUTTER_MANAGED_DIR})
51 |
52 | # Application build; see runner/CMakeLists.txt.
53 | add_subdirectory("runner")
54 |
55 | # Generated plugin build rules, which manage building the plugins and adding
56 | # them to the application.
57 | include(flutter/generated_plugins.cmake)
58 |
59 |
60 | # === Installation ===
61 | # Support files are copied into place next to the executable, so that it can
62 | # run in place. This is done instead of making a separate bundle (as on Linux)
63 | # so that building and running from within Visual Studio will work.
64 | set(BUILD_BUNDLE_DIR "$")
65 | # Make the "install" step default, as it's required to run.
66 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
67 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
68 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
69 | endif()
70 |
71 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
72 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
73 |
74 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
75 | COMPONENT Runtime)
76 |
77 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
78 | COMPONENT Runtime)
79 |
80 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
81 | COMPONENT Runtime)
82 |
83 | if(PLUGIN_BUNDLED_LIBRARIES)
84 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
85 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
86 | COMPONENT Runtime)
87 | endif()
88 |
89 | # Fully re-copy the assets directory on each build to avoid having stale files
90 | # from a previous install.
91 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
92 | install(CODE "
93 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
94 | " COMPONENT Runtime)
95 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
96 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
97 |
98 | # Install the AOT library on non-Debug builds only.
99 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
100 | CONFIGURATIONS Profile;Release
101 | COMPONENT Runtime)
102 |
--------------------------------------------------------------------------------
/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.14)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
12 |
13 | # Set fallback configurations for older versions of the flutter tool.
14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
15 | set(FLUTTER_TARGET_PLATFORM "windows-x64")
16 | endif()
17 |
18 | # === Flutter Library ===
19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
20 |
21 | # Published to parent scope for install step.
22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
26 |
27 | list(APPEND FLUTTER_LIBRARY_HEADERS
28 | "flutter_export.h"
29 | "flutter_windows.h"
30 | "flutter_messenger.h"
31 | "flutter_plugin_registrar.h"
32 | "flutter_texture_registrar.h"
33 | )
34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
35 | add_library(flutter INTERFACE)
36 | target_include_directories(flutter INTERFACE
37 | "${EPHEMERAL_DIR}"
38 | )
39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
40 | add_dependencies(flutter flutter_assemble)
41 |
42 | # === Wrapper ===
43 | list(APPEND CPP_WRAPPER_SOURCES_CORE
44 | "core_implementations.cc"
45 | "standard_codec.cc"
46 | )
47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
49 | "plugin_registrar.cc"
50 | )
51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
52 | list(APPEND CPP_WRAPPER_SOURCES_APP
53 | "flutter_engine.cc"
54 | "flutter_view_controller.cc"
55 | )
56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
57 |
58 | # Wrapper sources needed for a plugin.
59 | add_library(flutter_wrapper_plugin STATIC
60 | ${CPP_WRAPPER_SOURCES_CORE}
61 | ${CPP_WRAPPER_SOURCES_PLUGIN}
62 | )
63 | apply_standard_settings(flutter_wrapper_plugin)
64 | set_target_properties(flutter_wrapper_plugin PROPERTIES
65 | POSITION_INDEPENDENT_CODE ON)
66 | set_target_properties(flutter_wrapper_plugin PROPERTIES
67 | CXX_VISIBILITY_PRESET hidden)
68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
69 | target_include_directories(flutter_wrapper_plugin PUBLIC
70 | "${WRAPPER_ROOT}/include"
71 | )
72 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
73 |
74 | # Wrapper sources needed for the runner.
75 | add_library(flutter_wrapper_app STATIC
76 | ${CPP_WRAPPER_SOURCES_CORE}
77 | ${CPP_WRAPPER_SOURCES_APP}
78 | )
79 | apply_standard_settings(flutter_wrapper_app)
80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
81 | target_include_directories(flutter_wrapper_app PUBLIC
82 | "${WRAPPER_ROOT}/include"
83 | )
84 | add_dependencies(flutter_wrapper_app flutter_assemble)
85 |
86 | # === Flutter tool backend ===
87 | # _phony_ is a non-existent file to force this command to run every time,
88 | # since currently there's no way to get a full input/output list from the
89 | # flutter tool.
90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
92 | add_custom_command(
93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
95 | ${CPP_WRAPPER_SOURCES_APP}
96 | ${PHONY_OUTPUT}
97 | COMMAND ${CMAKE_COMMAND} -E env
98 | ${FLUTTER_TOOL_ENVIRONMENT}
99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
100 | ${FLUTTER_TARGET_PLATFORM} $
101 | VERBATIM
102 | )
103 | add_custom_target(flutter_assemble DEPENDS
104 | "${FLUTTER_LIBRARY}"
105 | ${FLUTTER_LIBRARY_HEADERS}
106 | ${CPP_WRAPPER_SOURCES_CORE}
107 | ${CPP_WRAPPER_SOURCES_PLUGIN}
108 | ${CPP_WRAPPER_SOURCES_APP}
109 | )
110 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | void RegisterPlugins(flutter::PluginRegistry* registry) {
19 | ConnectivityPlusWindowsPluginRegisterWithRegistrar(
20 | registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
21 | LaunchAtStartupPluginRegisterWithRegistrar(
22 | registry->GetRegistrarForPlugin("LaunchAtStartupPlugin"));
23 | ScreenRetrieverPluginRegisterWithRegistrar(
24 | registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
25 | SystemTrayPluginRegisterWithRegistrar(
26 | registry->GetRegistrarForPlugin("SystemTrayPlugin"));
27 | UrlLauncherWindowsRegisterWithRegistrar(
28 | registry->GetRegistrarForPlugin("UrlLauncherWindows"));
29 | WinToastPluginRegisterWithRegistrar(
30 | registry->GetRegistrarForPlugin("WinToastPlugin"));
31 | WindowManagerPluginRegisterWithRegistrar(
32 | registry->GetRegistrarForPlugin("WindowManagerPlugin"));
33 | WindowsSingleInstancePluginRegisterWithRegistrar(
34 | registry->GetRegistrarForPlugin("WindowsSingleInstancePlugin"));
35 | }
36 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | connectivity_plus
7 | launch_at_startup
8 | screen_retriever
9 | system_tray
10 | url_launcher_windows
11 | win_toast
12 | window_manager
13 | windows_single_instance
14 | )
15 |
16 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
17 | )
18 |
19 | set(PLUGIN_BUNDLED_LIBRARIES)
20 |
21 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
23 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
26 | endforeach(plugin)
27 |
28 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
29 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
31 | endforeach(ffi_plugin)
32 |
--------------------------------------------------------------------------------
/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(runner LANGUAGES CXX)
3 |
4 | # Define the application target. To change its name, change BINARY_NAME in the
5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 | # work.
7 | #
8 | # Any new source files that you add to the application should be added here.
9 | add_executable(${BINARY_NAME} WIN32
10 | "flutter_window.cpp"
11 | "main.cpp"
12 | "utils.cpp"
13 | "win32_window.cpp"
14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 | "Runner.rc"
16 | "runner.exe.manifest"
17 | )
18 |
19 | # Apply the standard set of build settings. This can be removed for applications
20 | # that need different build settings.
21 | apply_standard_settings(${BINARY_NAME})
22 |
23 | # Add preprocessor definitions for the build version.
24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 |
30 | # Disable Windows macros that collide with C++ standard library functions.
31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 |
33 | # Add dependency libraries and include directories. Add any application-specific
34 | # dependencies here.
35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
37 |
38 | # Run the Flutter tool portions of the build. This must not be removed.
39 | add_dependencies(${BINARY_NAME} flutter_assemble)
40 |
--------------------------------------------------------------------------------
/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0,0
67 | #endif
68 |
69 | #if defined(FLUTTER_VERSION)
70 | #define VERSION_AS_STRING FLUTTER_VERSION
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "BuildToApp" "\0"
93 | VALUE "FileDescription", "ir_net" "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "ir_net" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2022 BuildToApp. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "ir_net.exe" "\0"
98 | VALUE "ProductName", "ir_net" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 | return true;
30 | }
31 |
32 | void FlutterWindow::OnDestroy() {
33 | if (flutter_controller_) {
34 | flutter_controller_ = nullptr;
35 | }
36 |
37 | Win32Window::OnDestroy();
38 | }
39 |
40 | LRESULT
41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
42 | WPARAM const wparam,
43 | LPARAM const lparam) noexcept {
44 | // Give Flutter, including plugins, an opportunity to handle window messages.
45 | if (flutter_controller_) {
46 | std::optional result =
47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
48 | lparam);
49 | if (result) {
50 | return *result;
51 | }
52 | }
53 |
54 | switch (message) {
55 | case WM_FONTCHANGE:
56 | flutter_controller_->engine()->ReloadSystemFonts();
57 | break;
58 | case WM_CLOSE:
59 | ShowWindow(GetHandle(), SW_HIDE);
60 | return 0;
61 | break;
62 | }
63 |
64 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
65 | }
66 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.CreateAndShow(L"ir_net", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaherisaber/ir_net/86083a83e81e53efdf76cd43b1f2096091237ee6/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr);
51 | std::string utf8_string;
52 | if (target_length == 0 || target_length > utf8_string.max_size()) {
53 | return utf8_string;
54 | }
55 | utf8_string.resize(target_length);
56 | int converted_length = ::WideCharToMultiByte(
57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
58 | -1, utf8_string.data(),
59 | target_length, nullptr, nullptr);
60 | if (converted_length == 0) {
61 | return std::string();
62 | }
63 | return utf8_string;
64 | }
65 |
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/windows/runner/win32_window.cpp:
--------------------------------------------------------------------------------
1 | #include "win32_window.h"
2 |
3 | #include
4 |
5 | #include "resource.h"
6 |
7 | namespace {
8 |
9 | constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
10 |
11 | // The number of Win32Window objects that currently exist.
12 | static int g_active_window_count = 0;
13 |
14 | using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
15 |
16 | // Scale helper to convert logical scaler values to physical using passed in
17 | // scale factor
18 | int Scale(int source, double scale_factor) {
19 | return static_cast(source * scale_factor);
20 | }
21 |
22 | // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
23 | // This API is only needed for PerMonitor V1 awareness mode.
24 | void EnableFullDpiSupportIfAvailable(HWND hwnd) {
25 | HMODULE user32_module = LoadLibraryA("User32.dll");
26 | if (!user32_module) {
27 | return;
28 | }
29 | auto enable_non_client_dpi_scaling =
30 | reinterpret_cast(
31 | GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
32 | if (enable_non_client_dpi_scaling != nullptr) {
33 | enable_non_client_dpi_scaling(hwnd);
34 | FreeLibrary(user32_module);
35 | }
36 | }
37 |
38 | } // namespace
39 |
40 | // Manages the Win32Window's window class registration.
41 | class WindowClassRegistrar {
42 | public:
43 | ~WindowClassRegistrar() = default;
44 |
45 | // Returns the singleton registar instance.
46 | static WindowClassRegistrar* GetInstance() {
47 | if (!instance_) {
48 | instance_ = new WindowClassRegistrar();
49 | }
50 | return instance_;
51 | }
52 |
53 | // Returns the name of the window class, registering the class if it hasn't
54 | // previously been registered.
55 | const wchar_t* GetWindowClass();
56 |
57 | // Unregisters the window class. Should only be called if there are no
58 | // instances of the window.
59 | void UnregisterWindowClass();
60 |
61 | private:
62 | WindowClassRegistrar() = default;
63 |
64 | static WindowClassRegistrar* instance_;
65 |
66 | bool class_registered_ = false;
67 | };
68 |
69 | WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
70 |
71 | const wchar_t* WindowClassRegistrar::GetWindowClass() {
72 | if (!class_registered_) {
73 | WNDCLASS window_class{};
74 | window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
75 | window_class.lpszClassName = kWindowClassName;
76 | window_class.style = CS_HREDRAW | CS_VREDRAW;
77 | window_class.cbClsExtra = 0;
78 | window_class.cbWndExtra = 0;
79 | window_class.hInstance = GetModuleHandle(nullptr);
80 | window_class.hIcon =
81 | LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
82 | window_class.hbrBackground = 0;
83 | window_class.lpszMenuName = nullptr;
84 | window_class.lpfnWndProc = Win32Window::WndProc;
85 | RegisterClass(&window_class);
86 | class_registered_ = true;
87 | }
88 | return kWindowClassName;
89 | }
90 |
91 | void WindowClassRegistrar::UnregisterWindowClass() {
92 | UnregisterClass(kWindowClassName, nullptr);
93 | class_registered_ = false;
94 | }
95 |
96 | Win32Window::Win32Window() {
97 | ++g_active_window_count;
98 | }
99 |
100 | Win32Window::~Win32Window() {
101 | --g_active_window_count;
102 | Destroy();
103 | }
104 |
105 | bool Win32Window::CreateAndShow(const std::wstring& title,
106 | const Point& origin,
107 | const Size& size) {
108 | Destroy();
109 |
110 | const wchar_t* window_class =
111 | WindowClassRegistrar::GetInstance()->GetWindowClass();
112 |
113 | const POINT target_point = {static_cast(origin.x),
114 | static_cast(origin.y)};
115 | HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
116 | UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
117 | double scale_factor = dpi / 96.0;
118 |
119 | HWND window = CreateWindow(
120 | window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE,
121 | Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
122 | Scale(size.width, scale_factor), Scale(size.height, scale_factor),
123 | nullptr, nullptr, GetModuleHandle(nullptr), this);
124 |
125 | if (!window) {
126 | return false;
127 | }
128 |
129 | return OnCreate();
130 | }
131 |
132 | // static
133 | LRESULT CALLBACK Win32Window::WndProc(HWND const window,
134 | UINT const message,
135 | WPARAM const wparam,
136 | LPARAM const lparam) noexcept {
137 | if (message == WM_NCCREATE) {
138 | auto window_struct = reinterpret_cast(lparam);
139 | SetWindowLongPtr(window, GWLP_USERDATA,
140 | reinterpret_cast(window_struct->lpCreateParams));
141 |
142 | auto that = static_cast(window_struct->lpCreateParams);
143 | EnableFullDpiSupportIfAvailable(window);
144 | that->window_handle_ = window;
145 | } else if (Win32Window* that = GetThisFromHandle(window)) {
146 | return that->MessageHandler(window, message, wparam, lparam);
147 | }
148 |
149 | return DefWindowProc(window, message, wparam, lparam);
150 | }
151 |
152 | LRESULT
153 | Win32Window::MessageHandler(HWND hwnd,
154 | UINT const message,
155 | WPARAM const wparam,
156 | LPARAM const lparam) noexcept {
157 | switch (message) {
158 | case WM_DESTROY:
159 | window_handle_ = nullptr;
160 | Destroy();
161 | if (quit_on_close_) {
162 | PostQuitMessage(0);
163 | }
164 | return 0;
165 |
166 | case WM_DPICHANGED: {
167 | auto newRectSize = reinterpret_cast(lparam);
168 | LONG newWidth = newRectSize->right - newRectSize->left;
169 | LONG newHeight = newRectSize->bottom - newRectSize->top;
170 |
171 | SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
172 | newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
173 |
174 | return 0;
175 | }
176 | case WM_SIZE: {
177 | RECT rect = GetClientArea();
178 | if (child_content_ != nullptr) {
179 | // Size and position the child window.
180 | MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
181 | rect.bottom - rect.top, TRUE);
182 | }
183 | return 0;
184 | }
185 |
186 | case WM_ACTIVATE:
187 | if (child_content_ != nullptr) {
188 | SetFocus(child_content_);
189 | }
190 | return 0;
191 | }
192 |
193 | return DefWindowProc(window_handle_, message, wparam, lparam);
194 | }
195 |
196 | void Win32Window::Destroy() {
197 | OnDestroy();
198 |
199 | if (window_handle_) {
200 | DestroyWindow(window_handle_);
201 | window_handle_ = nullptr;
202 | }
203 | if (g_active_window_count == 0) {
204 | WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
205 | }
206 | }
207 |
208 | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
209 | return reinterpret_cast(
210 | GetWindowLongPtr(window, GWLP_USERDATA));
211 | }
212 |
213 | void Win32Window::SetChildContent(HWND content) {
214 | child_content_ = content;
215 | SetParent(content, window_handle_);
216 | RECT frame = GetClientArea();
217 |
218 | MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
219 | frame.bottom - frame.top, true);
220 |
221 | SetFocus(child_content_);
222 | }
223 |
224 | RECT Win32Window::GetClientArea() {
225 | RECT frame;
226 | GetClientRect(window_handle_, &frame);
227 | return frame;
228 | }
229 |
230 | HWND Win32Window::GetHandle() {
231 | return window_handle_;
232 | }
233 |
234 | void Win32Window::SetQuitOnClose(bool quit_on_close) {
235 | quit_on_close_ = quit_on_close;
236 | }
237 |
238 | bool Win32Window::OnCreate() {
239 | // No-op; provided for subclasses.
240 | return true;
241 | }
242 |
243 | void Win32Window::OnDestroy() {
244 | // No-op; provided for subclasses.
245 | }
246 |
--------------------------------------------------------------------------------
/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_WIN32_WINDOW_H_
2 | #define RUNNER_WIN32_WINDOW_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 | public:
15 | struct Point {
16 | unsigned int x;
17 | unsigned int y;
18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 | };
20 |
21 | struct Size {
22 | unsigned int width;
23 | unsigned int height;
24 | Size(unsigned int width, unsigned int height)
25 | : width(width), height(height) {}
26 | };
27 |
28 | Win32Window();
29 | virtual ~Win32Window();
30 |
31 | // Creates and shows a win32 window with |title| and position and size using
32 | // |origin| and |size|. New windows are created on the default monitor. Window
33 | // sizes are specified to the OS in physical pixels, hence to ensure a
34 | // consistent size to will treat the width height passed in to this function
35 | // as logical pixels and scale to appropriate for the default monitor. Returns
36 | // true if the window was created successfully.
37 | bool CreateAndShow(const std::wstring& title,
38 | const Point& origin,
39 | const Size& size);
40 |
41 | // Release OS resources associated with window.
42 | void Destroy();
43 |
44 | // Inserts |content| into the window tree.
45 | void SetChildContent(HWND content);
46 |
47 | // Returns the backing Window handle to enable clients to set icon and other
48 | // window properties. Returns nullptr if the window has been destroyed.
49 | HWND GetHandle();
50 |
51 | // If true, closing this window will quit the application.
52 | void SetQuitOnClose(bool quit_on_close);
53 |
54 | // Return a RECT representing the bounds of the current client area.
55 | RECT GetClientArea();
56 |
57 | protected:
58 | // Processes and route salient window messages for mouse handling,
59 | // size change and DPI. Delegates handling of these to member overloads that
60 | // inheriting classes can handle.
61 | virtual LRESULT MessageHandler(HWND window,
62 | UINT const message,
63 | WPARAM const wparam,
64 | LPARAM const lparam) noexcept;
65 |
66 | // Called when CreateAndShow is called, allowing subclass window-related
67 | // setup. Subclasses should return false if setup fails.
68 | virtual bool OnCreate();
69 |
70 | // Called when Destroy is called.
71 | virtual void OnDestroy();
72 |
73 | private:
74 | friend class WindowClassRegistrar;
75 |
76 | // OS callback called by message pump. Handles the WM_NCCREATE message which
77 | // is passed when the non-client area is being created and enables automatic
78 | // non-client DPI scaling so that the non-client area automatically
79 | // responsponds to changes in DPI. All other messages are handled by
80 | // MessageHandler.
81 | static LRESULT CALLBACK WndProc(HWND const window,
82 | UINT const message,
83 | WPARAM const wparam,
84 | LPARAM const lparam) noexcept;
85 |
86 | // Retrieves a class instance pointer for |window|
87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept;
88 |
89 | bool quit_on_close_ = false;
90 |
91 | // window handle for top level window.
92 | HWND window_handle_ = nullptr;
93 |
94 | // window handle for hosted content.
95 | HWND child_content_ = nullptr;
96 | };
97 |
98 | #endif // RUNNER_WIN32_WINDOW_H_
99 |
--------------------------------------------------------------------------------