├── .gitattributes ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── RELEASE.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── matrix │ │ │ │ └── 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 ├── archive ├── localStorage_todoMVC │ ├── common.cljd │ ├── core.cljd │ ├── footer.cljd │ ├── input.cljd │ ├── items.cljd │ ├── persist.cljd │ └── todo.cljd └── x045_websocket.cljd ├── audio ├── drum-1.mp3 ├── intro-1.mp3 ├── notify-1.mp3 ├── notify-2.mp3 └── scary.mp3 ├── clean.sh ├── cljd.edn ├── deps.edn ├── doc ├── flutter-tts-makeover.key ├── flutter-tts-makeover.pdf └── london clojurians October 2023 v2.pdf ├── examples ├── example │ ├── demo │ │ ├── ai │ │ │ └── gemini │ │ │ │ ├── advanced_text.cljd │ │ │ │ ├── advanced_text_stream.cljd │ │ │ │ ├── simple_chat.cljd │ │ │ │ ├── simple_text.cljd │ │ │ │ └── simple_text_and_image.cljd │ │ ├── boiler │ │ │ └── core.cljc │ │ ├── fmx_inspector │ │ │ ├── fmx_inspector.cljd │ │ │ └── tree_view.cljd │ │ ├── isolate │ │ │ ├── common.cljd │ │ │ ├── ixp │ │ │ │ ├── cheats.cljd │ │ │ │ ├── common.cljd │ │ │ │ ├── health.cljd │ │ │ │ ├── iso_control.cljd │ │ │ │ ├── ixp.cljd │ │ │ │ └── spawn_control.cljd │ │ │ ├── x00_compute.cljd │ │ │ ├── x00_spawn.cljd │ │ │ ├── x01_iso_explorer.cljd │ │ │ ├── x01_simple_bidirectional_link.cljd │ │ │ ├── x02_poc_mx_iso.cljd │ │ │ ├── x03_mx_isolate.cljd │ │ │ ├── x042_iso_toggle.cljd │ │ │ ├── x04_api_mx_iso.cljd │ │ │ └── x070_mqtt5.cljd │ │ ├── navigation │ │ │ ├── component.cljd │ │ │ ├── puzzle.cljd │ │ │ ├── trainer.cljd │ │ │ └── tree.cljd │ │ ├── parrot │ │ │ ├── component.cljd │ │ │ ├── core.cljd │ │ │ ├── fts.cljd │ │ │ ├── poetry.cljd │ │ │ └── stt │ │ │ │ ├── common.cljd │ │ │ │ ├── core.cljd │ │ │ │ └── recorder.cljd │ │ ├── todoMVC │ │ │ ├── common.cljd │ │ │ ├── core.cljd │ │ │ ├── footer.cljd │ │ │ ├── input.cljd │ │ │ ├── items.cljd │ │ │ ├── persist.cljd │ │ │ └── todo.cljd │ │ ├── todoMVX │ │ │ ├── README.md │ │ │ ├── common.cljd │ │ │ ├── core.cljd │ │ │ ├── footer.cljd │ │ │ ├── input.cljd │ │ │ ├── items.cljd │ │ │ ├── persist.cljd │ │ │ ├── state.cljd │ │ │ ├── supa.cljd │ │ │ ├── todo.cljd │ │ │ └── todoMVX.sql │ │ └── tts │ │ │ ├── component.cljd │ │ │ ├── core.cljd │ │ │ ├── draft.cljd │ │ │ ├── fts.cljd │ │ │ └── poetry.cljd │ ├── driver.cljc │ ├── eg │ │ ├── flutter_layout_tutorial.cljd │ │ ├── flutter_tts.cljd │ │ ├── x00_hello_world.cljd │ │ ├── x01_counter.cljd │ │ ├── x01_counter_desugared.cljd │ │ ├── x020_reactive_stream.cljd │ │ ├── x028_bottom_navbar.cljd │ │ ├── x029_layout_builder.cljd │ │ ├── x029a_layout_kid_builder.cljd │ │ ├── x02_two_counters_ala_flux.cljd │ │ ├── x02_two_counters_ala_matrix.cljd │ │ ├── x030_codelab_namer.cljd │ │ ├── x035_timer_poll.cljd │ │ ├── x03_physics_sim.cljd │ │ ├── x040_named_routes.cljd │ │ ├── x046_websocket_lob.cljd │ │ ├── x04_drawer.cljd │ │ ├── x050_just_audio.cljd │ │ ├── x055_isolates.cljd │ │ ├── x05_fab.cljd │ │ ├── x060_form_class.cljd │ │ ├── x065_autocomplete_basic.cljd │ │ ├── x066_autocomplete_object.cljd │ │ ├── x06_tabs.cljd │ │ ├── x070_speech_to_text.cljd │ │ ├── x07_animated_container.cljd │ │ ├── x08_navigation.cljd │ │ ├── x09_form_change.cljd │ │ ├── x09_form_input.cljd │ │ ├── x10_datatable.cljd │ │ ├── x11_grid_list.cljd │ │ ├── x12_gesture_detector.cljd │ │ ├── x13_snackbar.cljd │ │ ├── x14_hero.cljd │ │ ├── x15_fade_widget.cljd │ │ ├── x25_flutter_tex.cljd │ │ ├── x26_latex_sandbox.cljd │ │ └── x27_popup_menu.cljd │ └── non_fmx │ │ ├── ctx_row.cljd │ │ └── ifernandez_isolates.cljd └── learn │ └── counter │ └── counter_fmx.cljd ├── fonts ├── Inter-Regular.ttf ├── RobotoMono-Light.ttf └── RobotoMono-Thin.ttf ├── goopi.sh ├── image ├── 800px-Depth-first-tree.svg.png ├── Depth-First-Search.gif ├── HW d Sim.png ├── HW d all.png ├── HW d chrome.png ├── HW d macos.png ├── cat_on_snow.jpeg ├── counter-app.png ├── earth.png ├── einstein.jpeg ├── game-over.png ├── hello-world-app.jpg ├── jmccarthy.jpeg ├── john.jpeg ├── kenny-naut.png ├── kernighan.jpeg ├── lake-oeschinen.jpeg ├── scone.jpeg ├── todomvc-app.jpeg ├── trophy.jpeg └── under-construction.jpeg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── 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 └── RunnerTests │ └── RunnerTests.swift ├── lib └── main.dart ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── 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 └── RunnerTests │ └── RunnerTests.swift ├── other ├── flutter-fab.dart └── physics_sim_std.cljd ├── pom.xml ├── pubspec.yaml ├── src └── tilton │ ├── counter_app.cljc │ ├── fmx │ ├── api.cljd │ ├── factory.cljd │ ├── material.cljd │ └── widgets.cljd │ ├── main.cljd │ ├── mx │ ├── api.cljd │ ├── base.cljd │ ├── cell │ │ ├── base.cljd │ │ ├── core.cljd │ │ ├── evaluate.cljd │ │ ├── integrity.cljd │ │ ├── observer.cljd │ │ └── synapse.cljd │ ├── foundation.cljd │ ├── model │ │ ├── base.cljd │ │ ├── core.cljd │ │ ├── navigate.cljd │ │ └── peek.cljd │ └── util.cljd │ ├── test │ ├── cell_core.cljd │ ├── evaluate.cljd │ ├── family_kids.cljd │ ├── hello_cells.cljd │ ├── integrity.cljd │ ├── lazy_cells.cljd │ ├── model_core.cljd │ ├── observer.cljd │ └── synapse.cljd │ └── testing.cljd ├── sup.sh ├── sup_macos.sh ├── supmvx.sh ├── supweb.sh ├── 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 /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cljd linguist-language=Clojure 2 | # Syntax highlighting for ClojureDart files 3 | *.cljd linguist-language=Clojure 4 | 5 | # Syntax highlighting for ClojureDart files 6 | *.cljd linguist-language=Clojure 7 | 8 | # Syntax highlighting for ClojureDart files 9 | *.cljd linguist-language=Clojure 10 | 11 | # Syntax highlighting for ClojureDart files 12 | *.cljd linguist-language=Clojure 13 | 14 | # Syntax highlighting for ClojureDart files 15 | *.cljd linguist-language=Clojure 16 | 17 | # Syntax highlighting for ClojureDart files 18 | *.cljd linguist-language=Clojure 19 | 20 | # Syntax highlighting for ClojureDart files 21 | *.cljd linguist-language=Clojure 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | .nrepl-port 12 | 13 | demo-video 14 | linux 15 | android 16 | other 17 | out 18 | 19 | # IntelliJ related 20 | *.iml 21 | *.ipr 22 | *.iws 23 | .idea/ 24 | 25 | # The .vscode folder contains launch configuration and tasks you configure in 26 | # VS Code which you may wish to be included in version control, so this line 27 | # is commented out by default. 28 | #.vscode/ 29 | 30 | # Flutter/Dart/Pub related 31 | **/doc/api/ 32 | **/ios/Flutter/.last_build_id 33 | .flutter-plugins 34 | .flutter-plugins-dependencies 35 | .packages 36 | .pub-cache/ 37 | .pub/ 38 | /build/ 39 | /lib/cljd-out/ 40 | /ios/build/ 41 | /test/ 42 | 43 | .cpcache 44 | .lsp/.cache 45 | .clj-kondo/* 46 | .clojuredart 47 | .dart_tool 48 | pubspec.lock 49 | 50 | 51 | # Web related 52 | 53 | # Symbolication related 54 | app.*.symbols 55 | 56 | # Obfuscation related 57 | app.*.map.json 58 | 59 | # Android Studio will place build artifacts here 60 | /android/app/debug 61 | /android/app/profile 62 | /android/app/release 63 | 64 | # ClojureDart 65 | .cpcache/ 66 | .clojuredart/ 67 | lib/cljd-out/ 68 | test/cljd-out/ 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /.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: f468f3366c26a5092eb964a230ce7892fda8f2f8 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: f468f3366c26a5092eb964a230ce7892fda8f2f8 17 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 18 | - platform: android 19 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 20 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 21 | - platform: ios 22 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 23 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 24 | - platform: linux 25 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 26 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 27 | - platform: macos 28 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 29 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 30 | - platform: web 31 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 32 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 33 | - platform: windows 34 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 35 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Kenneth Tilton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.example.matrix" 47 | minSdkVersion flutter.minSdkVersion 48 | targetSdkVersion flutter.targetSdkVersion 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/matrix/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.matrix 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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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:4.1.0' 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 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /archive/localStorage_todoMVC/common.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.localStorage-todoMVC.common 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:shared_preferences/shared_preferences.dart" :as prefs])) 5 | 6 | (defn title-red [] 7 | (.fromRGBO m/Color 184 63 69 0.5)) 8 | 9 | (defmacro my-todo-list [] 10 | `(tilton.mx.model.base/mget 11 | (tilton.mx.model.core/fasc :app) 12 | :todo-list)) 13 | -------------------------------------------------------------------------------- /archive/localStorage_todoMVC/input.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.localStorage-todoMVC.input 2 | (:require 3 | ["package:flutter/widgets.dart" :as w] 4 | ["package:flutter/material.dart" :as m] 5 | ["package:flutter/painting.dart" :as p] 6 | [clojure.string :as str] 7 | [tilton.mx.api :refer [cF cI cFonce mget mswap! mset!]] 8 | [tilton.fmx.api :refer [dart-cb my-app] :as fx] 9 | [example.demo.localStorage-todoMVC.common :refer [ my-todo-list ] :as cmm] 10 | [example.demo.localStorage-todoMVC.todo :refer [td-completed] :as todo])) 11 | 12 | (defn todo-input-onSubmitted-formula [] 13 | (cF (dart-cb [value] 14 | ;; blank or not we need to restore focus to the input per the spec 15 | (.requestFocus ^m/FocusNode (mget me :focusNode)) 16 | ;; spec says to trim, and to silently ignore blank entry 17 | (let [trimmed (str/trim value)] 18 | (when-not (str/blank? trimmed) 19 | ;; --- we have a non-blank entry, so we save, clear entry, and store 20 | (mset! me :value trimmed) ;; let text proxy know its cleaned value 21 | (.clear ^m/TextEditingController 22 | (mget me :controller)) 23 | (let [td-lst (my-todo-list)] 24 | (mswap! td-lst :kids conj 25 | (todo/make-ToDo td-lst trimmed false)))))))) 26 | 27 | (defn todo-input [] 28 | (fx/material {:elevation 20.0 29 | :color m/Colors.white 30 | :shadowColor m/Colors.black} 31 | (fx/text-field {:autofocus true 32 | :focusNode (m/FocusNode) 33 | :decoration (m/InputDecoration 34 | .hintText "What needs doing?" 35 | .border m.InputBorder/none 36 | .contentPadding (m/EdgeInsets.all 9.0)) 37 | :onSubmitted (todo-input-onSubmitted-formula) 38 | :controller (cFonce (fx/text-field-controller-basic me))} 39 | {:name :todo-input 40 | ;; todo get prefill working. standard controller not picking up value 41 | :value (cI "test")}))) 42 | 43 | (defn todo-toggle-all [] 44 | (fx/visibility 45 | {:visible (cF (boolean 46 | (seq (todo/app-todos (my-app))))) 47 | ;; todo: composability with fixed arity reusables as case may be. 48 | :maintainSize true 49 | :maintainSemantics false 50 | ;; todo why do not other visis specify these ^^^ vvvv? 51 | :maintainInteractivity false 52 | :maintainAnimation true 53 | :maintainState true} 54 | (fx/icon-button 55 | {:onPressed (dart-cb [] 56 | (let [todos (todo/app-todos (my-app)) 57 | all-done? (every? td-completed todos)] 58 | (doseq [td todos] 59 | ;; todo do all these in one change pulse 60 | (mset! td :completed (if all-done? false true))))) 61 | :icon (m/Icon m.Icons/expand_more .color m/Colors.blueGrey)}))) 62 | 63 | (defn todo-controls [] 64 | (fx/row 65 | (fx/expanded {:flex 1} 66 | ;; handy widget to mark all to-dos at once 67 | (todo-toggle-all)) 68 | ; --- the to-do input field ---- 69 | (fx/expanded {:flex 9} 70 | (fx/padding 71 | {:padding (m/EdgeInsets.all 16.0)} 72 | (todo-input))))) -------------------------------------------------------------------------------- /archive/localStorage_todoMVC/persist.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.localStorage-todoMVC.persist 2 | (:require 3 | ["package:shared_preferences/shared_preferences.dart" :as prefs] 4 | ["dart:convert" :as convert] 5 | ["package:uuid/uuid.dart" :as uu] 6 | [tilton.mx.base :refer [dprn dp dpx]] 7 | [tilton.mx.util :as util] 8 | [clojure.walk :as walk])) 9 | 10 | (def +DB+ (atom nil)) ;; n.b. just a cache, NOT reactive 11 | (defn ^prefs/SharedPreferences? DB [] (deref +DB+)) 12 | (defn ^prefs/SharedPreferences? DB! [db] (reset! +DB+ db)) 13 | 14 | (def +uuid+ (atom nil)) 15 | (defn ^uu/Uuid UUID [] 16 | (or (deref +uuid+) 17 | (uu/Uuid))) 18 | 19 | (defn td-store 20 | "Write a CLJD ToDo map to persistent storage. 21 | Map must contain :stg-id, a string identifier. 22 | Returns the stg-id." 23 | [td-map] 24 | (let [stg-id (:stg-id td-map)] 25 | (assert stg-id "td-rewrite map must include stg-id") 26 | (.setString (DB) stg-id 27 | (convert/jsonEncode 28 | (walk/stringify-keys 29 | (select-keys td-map 30 | [:stg-id :created-at :title :completed])))) 31 | stg-id)) 32 | 33 | (defn td-initialize 34 | "Create a SharedPrefs to-do from a CLJD map alone. 35 | Returns the unique storage key generated for the data." 36 | [collection-name td-map] 37 | (when-let [stg-id (:stg-id td-map)] 38 | (throw (Exception. (str "td-initialize> sees :stg-id " stg-id ", suggesting td already written")))) 39 | 40 | (let [new-stg-id (str collection-name "/" (.v4 (UUID)))] 41 | (td-store 42 | (assoc td-map :stg-id new-stg-id)) 43 | new-stg-id)) 44 | 45 | (defn td-rewrite 46 | "Update a stored to-do given only a CLJD map of its properties. 47 | Map must contain non-nil :stg-id." 48 | [td-map] 49 | (assert (:stg-id td-map) 50 | "td-rewrite> map must include stg-id") 51 | (td-store td-map) 52 | (:stg-id td-map)) 53 | 54 | (defn td-delete 55 | "Deletes storage associated with stg-id." 56 | [stg-id] 57 | (assert stg-id "td-delete> stg-id argument is nil. s/b string ID.") 58 | (.remove (DB) stg-id) 59 | stg-id) 60 | 61 | ;;; --- collection-level utilities ------------- 62 | 63 | (defn collection-docs [collection-name] 64 | (let [all-td-keys (collection-keys collection-name)] 65 | (mapv (fn [td-key] 66 | (util/dart-map->cljd-map 67 | (convert/jsonDecode (.getString (DB) td-key)))) 68 | all-td-keys))) 69 | 70 | (defn collection-keys [collection-name] 71 | (into #{} 72 | (filter #(= collection-name 73 | (subs % 0 (count collection-name))) 74 | (.getKeys (DB))))) 75 | 76 | (defn collection-delete-all [collection-name] 77 | (doseq [k (collection-keys collection-name)] 78 | (td-delete k))) -------------------------------------------------------------------------------- /audio/drum-1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/audio/drum-1.mp3 -------------------------------------------------------------------------------- /audio/intro-1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/audio/intro-1.mp3 -------------------------------------------------------------------------------- /audio/notify-1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/audio/notify-1.mp3 -------------------------------------------------------------------------------- /audio/notify-2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/audio/notify-2.mp3 -------------------------------------------------------------------------------- /audio/scary.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/audio/scary.mp3 -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # shut down any builder 4 | 5 | # on sim: 6 | # - erase all content 7 | # - restart 8 | 9 | # in repo: 10 | touch pubspec.yaml 11 | rm -rf .clojuredart 12 | rm -rf lib/cljd-out 13 | flutter clean 14 | 15 | # now: clj -M -m cljd.build flutter -------------------------------------------------------------------------------- /cljd.edn: -------------------------------------------------------------------------------- 1 | {:main tilton.main, :bin "flutter"} -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "examples" ] 2 | :cljd/opts {:kind :flutter 3 | :main tilton.main} 4 | :aliases {:cljd {:main-opts ["-m" "cljd.build"]}} 5 | :deps {org.clojure/data.json {:mvn/version "2.4.0"} 6 | tensegritics/clojuredart 7 | {:git/url "https://github.com/Tensegritics/ClojureDart.git" 8 | :sha "6127d8ef23156f2be5b10e97a0932868d175e585" #_"0e1ef256cf3a0ee9b71db6d4af3d8be581b95195" #_"98463fae4e5fe50566b38e688cfed78071ea91a1"}}} 9 | -------------------------------------------------------------------------------- /doc/flutter-tts-makeover.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/doc/flutter-tts-makeover.key -------------------------------------------------------------------------------- /doc/flutter-tts-makeover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/doc/flutter-tts-makeover.pdf -------------------------------------------------------------------------------- /doc/london clojurians October 2023 v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/doc/london clojurians October 2023 v2.pdf -------------------------------------------------------------------------------- /examples/example/demo/boiler/core.cljc: -------------------------------------------------------------------------------- 1 | (ns example.demo.boiler.core 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | [tilton.mx.cell.base :as cty] 6 | [tilton.mx.model.core :refer [make]] 7 | [tilton.mx.api :refer [dp minfo cF cI cFn cFonce mmx-md mget mset! mswap! fm* fmu fasc mav] :as mx] 8 | [tilton.fmx.api :as fx 9 | :refer [dart-cb within-ctx 10 | material-app scaffold app-bar floating-action-button 11 | center column text sized-box]])) 12 | 13 | (defn make-app [] 14 | (cty/cells-reset) 15 | (let [b (make :on? (tilton.mx.cell.core/make-cell 16 | :watch (fn [slot me new prior c] 17 | (dp :CHG! slot :now new :was prior)) 18 | :value true 19 | :input? true) 20 | :burner (tilton.mx.cell.core/make-c-formula 21 | :watch (fn [slot me new prior c] 22 | (dp :CHG! slot :now new :was prior)) 23 | :rule (tilton.mx.cell.core/c-fn 24 | (if (mget me :on?) 25 | :blasting :off))) 26 | #_ (cF (if (mget me :on?) 27 | :blasting :off)))] 28 | ;(dp :startxx :on (mget b :on?) :burner-on (mget b :burner)) 29 | ;;(mset! b :burner :off) ;; todo fails on wrong error, but only if :on? is not cI 30 | (mset! b :on? false) 31 | #_ (dp :post-on-false :on (mget b :on?) :burner-on (mget b :burner))) 32 | 33 | (let [title "Boiler Demo X"] 34 | (material-app 35 | {:title title 36 | :theme (m/ThemeData .useMaterial3 true 37 | .colorScheme (m/ColorScheme.fromSeed 38 | .seedColor m/Colors.deepPurple))} 39 | (scaffold 40 | {:appBar (app-bar 41 | {:title (m/Text title) 42 | :backgroundColor (cF (.-inversePrimary 43 | (.-colorScheme ^m/ThemeData (mav :theme))))}) 44 | 45 | ;---------- how abaout fma-get, -set!, -swap! ???? 46 | 47 | :floatingActionButton 48 | (floating-action-button 49 | {:onPressed (dart-cb [] 50 | (mswap! (fm* :counter) :value inc)) 51 | :tooltip "Increment"} 52 | (m/Icon m/Icons.add .color m/Colors.black))} 53 | (center 54 | (column {:mainAxisAlignment m/MainAxisAlignment.center} 55 | (text {:style (p/TextStyle .color m/Colors.black 56 | .fontSize 20.0)} 57 | "The button push count now:") 58 | (sized-box 59 | {:height 28.0}) 60 | (text 61 | {:style (cF (fx/within-ctx [me ctx] 62 | (-> (m/Theme.of ctx) .-textTheme .-displayMedium)) 63 | #_(.-displayLarge (.-textTheme ^m/ThemeData (mav :theme))))} 64 | {:name :counter 65 | :value (cI 0)} 66 | (str (mget me :value))))))))) 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /examples/example/demo/fmx_inspector/fmx_inspector.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.fmx-inspector.fmx-inspector 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | ["package:english_words/english_words.dart" :as en] 7 | [tilton.mx.api :refer [minfo dpx dp cF cFn cI mget mset! mupdate! mav fasc fmu muv] :as mx] 8 | [tilton.mx.model.peek :refer [mname]] 9 | [tilton.fmx.api :refer [center column text sized-box dart-cb] :as fx] 10 | [example.demo.fmx-inspector.tree-view :as tv] 11 | [learn.counter.counter-fmx :as ctr])) 12 | 13 | 14 | ;;; --- utils --------------------------------------------- 15 | 16 | (defmacro even-row [& parts] 17 | `(row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 18 | ~@parts)) 19 | 20 | (defmacro app-section [& parts] 21 | `(column 22 | (m/Divider .thickness 0.5 .color m/Colors.grey) 23 | ~@parts)) 24 | 25 | (defn mk-condensed? [] 26 | ; (fx/sized-box {:width 300} 27 | (fx/checkbox-list-tile 28 | {:controlAffinity m/ListTileControlAffinity.leading 29 | :title (m/Text "condensed") 30 | :value (cF (mav :condensed?)) 31 | :onChanged (cF (dart-cb [value] 32 | (mset! (fasc :inspector) :condensed? value)))} 33 | {:name :condensed?})) 34 | 35 | ;;; --- inspector ---------------------------------------- 36 | 37 | (defn inspector-page [target excluding] 38 | (column {} 39 | {:name :inspector 40 | :target (cFn (fmu target)) 41 | :condensed? (cI false) 42 | :selected-cell (cI #{})} 43 | (app-section 44 | (mk-condensed?)) 45 | (app-section 46 | (fx/single-child-scroll-view 47 | {:scrollDirection m/Axis.horizontal} 48 | (fx/container 49 | {:constraints (m/BoxConstraints .minHeight 24) 50 | :margin (m/EdgeInsets.all 3) 51 | :decoration (cF (fx/box-decoration 52 | {:border (cF (.all m/Border .color m/Colors.blue .width 0.5)) 53 | :color m/Colors.grey.shade50}))} 54 | (let [tgt (mav :target)] 55 | (dpx :top-tgt tgt) 56 | (tv/md-tree-view tgt))))))) 57 | 58 | ;;; --- make-app --------------------------------------------------------------- 59 | 60 | (defn make-app 61 | [] 62 | (let [title "f/mx Inspector"] 63 | (fx/material-app {:title title 64 | :theme (m/ThemeData .fontFamily "RobotoMon")} 65 | (fx/default-tab-controller 66 | {:length 2 :initialIndex 0} 67 | (fx/scaffold 68 | {:appBar (fx/app-bar 69 | {:bottom (m/TabBar .tabs [(m/Tab .icon (m/Icon m/Icons.home .size 48)) 70 | (m/Tab .icon (m/Icon m/Icons.public .size 48))])})} 71 | (fx/tab-bar-view 72 | (center {} 73 | {:name :blackjack} 74 | (ctr/home-page .title "Blackjack-ish")) 75 | (center {} 76 | {:name :inspector-socket} 77 | (inspector-page :blackjack nil)))))))) -------------------------------------------------------------------------------- /examples/example/demo/isolate/ixp/cheats.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.ixp.cheats) 2 | 3 | (comment 4 | 5 | 6 | (doto (.-instance m/WidgetsBinding) 7 | (.addPostFrameCallback 8 | (fn [^Duration d]))) 9 | 10 | (defmacro post-frame [[duration-var] & body] 11 | `(doto (.-instance m/WidgetsBinding) 12 | (.addPostFrameCallback 13 | (fn [^Duration ~duration-var] 14 | ~@body)))) 15 | 16 | (.-millisecondsSinceEpoch (.now DateTime))) -------------------------------------------------------------------------------- /examples/example/demo/isolate/ixp/common.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.ixp.common 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | [tilton.mx.api :as mx 7 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 8 | fmu muv fm* mav mx-bound? wmx-iso with-cc millis-now or-mx-bound]])) 9 | 10 | (defmacro result-clear [] 11 | ; todo move to common 12 | `(tilton.mx.api/mset! (tilton.mx.api/fasc :app) :worker-msg 13 | {:msg-type :clear})) -------------------------------------------------------------------------------- /examples/example/demo/isolate/ixp/health.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.ixp.health 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | ["dart:io" :as io] 7 | ["dart:async" :as async] 8 | ["dart:convert" :as convert] 9 | [tilton.mx.api :as mx 10 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! wmx-iso millis-now or-mx-bound]] 11 | [tilton.fmx.api :as fx 12 | :refer [scaffold app-bar text center column hero material-app 13 | container row expanded icon padding opacity ignore-pointer 14 | checkbox-list-tile icon-button fx-render dart-cb]] 15 | [example.demo.isolate.common :as cmn 16 | :refer [iso-ping]] 17 | ["dart:isolate" :as di 18 | :refer [Isolate SendPort Capability ReceivePort]])) 19 | 20 | (defonce HCINTERVAL 200) 21 | 22 | (defn mk-health-monitor [app iso to-iso] 23 | (mx/make 24 | ;; health 25 | :name :health-monitor 26 | :health-clock (cF+ [:watch (fn [_ _ _ prior _] 27 | (when (dart/is? prior async/Timer) 28 | (.cancel ^async/Timer prior))) 29 | :on-quiesce (fn [c] (when-let [tmr ^async/Timer (mx/c-value c)] 30 | (dp :ONQ-health-cancel!!!!!!!!!!!!!!!) 31 | (.cancel tmr)))] 32 | (async/Timer.periodic (Duration .milliseconds HCINTERVAL) 33 | (fn [^async/Timer tmr] 34 | (wmx-iso 35 | (mset! me :health-check 36 | {:msg-type "health-check" 37 | :epoch (millis-now)}))))) 38 | :health-ack (cF (let [{:keys [msg-type response] :as msg} (mget app :worker-msg)] 39 | (cond 40 | (or (nil? msg) 41 | (not= :health-check-ack msg-type)) 42 | (or-mx-bound _cache nil) 43 | :else response))) 44 | 45 | :health-check (cI nil :watch (fn [_ me check _ _] 46 | (when check 47 | (iso-ping iso to-iso 48 | Isolate.beforeNextEvent 49 | check)))) 50 | 51 | :health (cF (if-let [chk (mget me :health-check)] 52 | (let [ack (mget me :health-ack) 53 | delta (cond 54 | (nil? ack) (- (millis-now) (:epoch chk)) 55 | (< (:epoch ack) (:epoch chk)) (- (:epoch chk) (:epoch ack)) 56 | :else (- (:epoch ack) (:epoch chk)))] 57 | (cond 58 | (>= delta (* 5 HCINTERVAL)) :dead 59 | (>= delta (* 1.5 HCINTERVAL)) :slow 60 | :else :healthy)) 61 | :unchecked)))) -------------------------------------------------------------------------------- /examples/example/demo/isolate/ixp/iso_control.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.ixp.iso-control 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | ["package:flutter/foundation.dart" :as fnd] 7 | ["dart:convert" :as convert] 8 | ["dart:math" :as math] 9 | [clojure.string :as str] 10 | [clojure.walk :as walk] 11 | [tilton.mx.api :as mx 12 | :refer [dp dpx cI cF cF+ mget mget? mset! mswap! minfo fasc 13 | mav with-cc millis-now or-mx-bound]] 14 | [tilton.fmx.api :as fx 15 | :refer [scaffold app-bar text center column hero material-app 16 | container row expanded icon padding opacity ignore-pointer 17 | checkbox-list-tile icon-button fx-render dart-cb]] 18 | 19 | ["dart:isolate" :as di 20 | :refer [Isolate SendPort ReceivePort]] 21 | [example.demo.isolate.common 22 | :refer [clock-face slow-is-prime? just-slow-is-prime? 23 | dbgiso iso-name say-delay m99 iso-ping]] 24 | [example.demo.isolate.ixp.common :refer [result-clear]])) 25 | 26 | ;;; --- job starters ----------- 27 | 28 | (defn decide-in-main [n] 29 | (fx/elevated-button 30 | {:onPressed (cF (dart-cb [] 31 | (result-clear) 32 | (doto (.-instance m/WidgetsBinding) 33 | (.addPostFrameCallback 34 | (fn [^Duration d] 35 | (mset! (fasc :app) :worker-msg 36 | {:msg-type :prime-decision 37 | :method "Main.iso" 38 | :n n 39 | :value (just-slow-is-prime? n)}))))))} 40 | (m/Text (str "Main " (m99 n))))) 41 | 42 | (defn decide-in-compute [n] 43 | (fx/elevated-button 44 | {:onPressed (cF (dart-cb [] 45 | (result-clear) 46 | (mset! me :compute? true)))} 47 | {:compute? (cI false :ephemeral? true) 48 | :result (cF+ [:async? true 49 | :watch (fn [_ me new _ _] 50 | (when (not (nil? new)) 51 | (with-cc :worker-res 52 | (mset! (fasc :app) :worker-msg 53 | {:msg-type :prime-decision 54 | :method "fnf/compute" 55 | :n n 56 | :value new}))))] 57 | (when (mget me :compute?) 58 | (fnd/compute just-slow-is-prime? n)))} 59 | (m/Text (str "Compute " (m99 n))))) 60 | 61 | (defn decide-in-run [n] 62 | (fx/elevated-button 63 | {:onPressed (dart-cb [] 64 | (result-clear) 65 | (mset! (fasc :app) :run-job 66 | {:msg-type :decide-prime 67 | :n n 68 | :id (millis-now) 69 | :method "Iso.run"}))} 70 | (m/Text (str "Iso.run " (m99 n))))) 71 | 72 | ;;; --- worker result ----------------------------------------------- 73 | 74 | (defn worker-msg-display [] 75 | (text {:style (p/TextStyle .fontSize 16)} 76 | (let [{:keys [method msg-type n value] :as result} (mav :worker-msg)] 77 | (dpx :result msg-type n value method) 78 | (case msg-type 79 | :prime-decision (str (or method "Anon") " says " (or n "NIL") " is " (when-not value "NOT ") "prime.") 80 | :ping-ack (:response result) 81 | :alert (:msg result) 82 | :clear "..." 83 | (or-mx-bound _cache ""))))) 84 | 85 | -------------------------------------------------------------------------------- /examples/example/demo/isolate/x00_compute.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.x00-compute 2 | (:require 3 | ["package:flutter/gestures.dart" :as g] 4 | ["package:flutter/material.dart" :as m 5 | :refer [Canvas Size]] 6 | ["package:flutter/painting.dart" :as p] 7 | ["package:vector_math/vector_math_64.dart" :as vm] 8 | ["dart:math" :as math 9 | :refer [pi cos sin]] 10 | ["dart:async" :as async 11 | :refer [Completer StreamSubscription]] 12 | ["dart:isolate" :as di 13 | :refer [Isolate SendPort ReceivePort]] 14 | ["package:flutter/foundation.dart" :as fnd] 15 | 16 | [tilton.mx.cell.base :as cb] 17 | [tilton.mx.api :as mx 18 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 19 | navig fmu muv fm* mav mx-bound? wmx-iso with-cc]] 20 | [tilton.fmx.api :as fx] 21 | [example.demo.isolate.common :as cmn 22 | :refer [clock-face slow-is-prime? dbgiso]])) 23 | 24 | (defn use-compute? [starting] 25 | (fx/sized-box {:width 300} 26 | (fx/checkbox-list-tile 27 | {:controlAffinity m/ListTileControlAffinity.leading 28 | :title (m/Text "Use Foundation/compute?" 29 | .style (p/TextStyle 30 | .fontSize 24)) 31 | :value (cI starting) 32 | :onChanged (cF #(wmx-iso 33 | (mset! me :value %) 34 | (mset! (fmu :primer) :of 9000039)))} 35 | {:name :use-compute?}))) 36 | 37 | (declare prime-decision) 38 | 39 | (defn make-app [] 40 | (let [title "Smooth Clock"] 41 | (fx/material-app 42 | {:title title} 43 | (fx/scaffold 44 | {:appBar (fx/app-bar {:title (fx/text title)}) 45 | :floatingActionButton 46 | (fx/floating-action-button 47 | {:onPressed (fx/dart-cb [] 48 | (wmx-iso 49 | (mswap! (fmu :primer) :of + 2)))} 50 | (m/Icon m/Icons.play_arrow 51 | .color m/Colors.black))} 52 | (fx/column 53 | {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 54 | (clock-face) 55 | (use-compute? false) 56 | (fx/row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 57 | (fx/text {:style (p/TextStyle .fontSize 24)} 58 | {:name :primer 59 | :of (cI 9000039) 60 | :prime? (cF+ [:async? true] 61 | (let [n (mget me :of) 62 | use? (mx/muv :use-compute?)] 63 | (if use? 64 | (fnd/compute slow-is-prime? n) 65 | (future (slow-is-prime? n)))))} 66 | "" #_(str "Is " (mget me :of) " prime? ")) 67 | ; ... results: 68 | (prime-decision)) 69 | (fx/text {:style (p/TextStyle .fontSize 16)} 70 | "Tap for next in 9000041,.49,.59,.67,..")))))) 71 | 72 | (defn prime-decision [] 73 | (fx/sized-box {:height 32} 74 | (fx/text 75 | {:style (cF (let [{:keys [prime?]} (mget (fmu :primer) :prime?)] 76 | (fx/text-style 77 | {:fontSize 24 78 | :fontWeight m/FontWeight.w400 79 | :color (if prime? m/Colors.green m/Colors.red)})))} 80 | {:name :prime-dec-text} 81 | (let [{:keys [of prime?]} (mget (fmu :primer) :prime?)] 82 | (dpx :decision-sees of :prime? prime?) 83 | (str "Is " of " prime? " 84 | (cond 85 | (nil? prime?) "..." 86 | (true? prime?) "Yep!!" 87 | (false? prime?) "Nope" 88 | :else "#@!%")))))) 89 | -------------------------------------------------------------------------------- /examples/example/demo/isolate/x00_spawn.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.x00-spawn 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | [clojure.string :as str] 7 | [tilton.mx.api :as mx 8 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 9 | fmu muv fm* mav mx-bound? wmx-iso]] 10 | [tilton.fmx.api :as fx 11 | :refer [scaffold app-bar text center column hero material-app 12 | container row expanded icon padding opacity ignore-pointer 13 | checkbox-list-tile icon-button fx-render dart-cb]] 14 | [example.demo.isolate.common :as cmn 15 | :refer [clock-face slow-is-prime? dbgiso say-delay]] 16 | ["dart:isolate" :as di 17 | :refer [Isolate SendPort ReceivePort]])) 18 | 19 | ;;; Inspired by Plague Fox, Example 1: https://plugfox.dev/mastering-isolates/ 20 | ;;; 21 | ;;; we do nothing but spawn an isolate, watch it run, and watch it exit 22 | ;;; 23 | ;;; but play around with commenting/uncommenting below the delays and kills, etc, to get 24 | ;;; a feel for async and isolates. 25 | 26 | (defn factorial-worker [n] 27 | (dbgiso :worker-entry) 28 | (reduce (fn [a b] 29 | (let [f (* a b)] 30 | (dp :factorial-of b :is f) 31 | f)) 32 | (range 1 (inc n))) 33 | ; (await (say-delay 2 :worker-pre-return)) 34 | ; (await (Future.delayed (Duration .seconds 2))) 35 | 36 | ; if we do not trust dart:io to kill an iso on return... 37 | (do 38 | (dbgiso :worker-pre-exit) 39 | (Isolate.exit) 40 | (dp :YOU_SHOULD_NOT_SEE_THIS_WE_EXITED!!!!!!!!!!!!)) 41 | ) 42 | 43 | (defn make-app [] 44 | (fx/material-app {} 45 | {:iso (cF+ [:async? true 46 | :watch (fn [_ me new-iso _ _] 47 | (dbgiso :watch-sees-new-iso new-iso) 48 | #_ (when new-iso 49 | (say-delay 1 :main-watch-pre-kill) 50 | (.kill ^Isolate new-iso .priority Isolate.immediate) 51 | ;(.kill ^Isolate new-iso .priority Isolate.beforeNextEvent) 52 | ;; nb: iso debugname still retrievable with either kill priority 53 | (dbgiso :watch-just-killed-iso new-iso)))] 54 | (Isolate.spawn 55 | factorial-worker 5))} 56 | (fx/scaffold 57 | {:appBar (fx/app-bar {:title (fx/text "Intentionally Left Blank (see console)")})}))) -------------------------------------------------------------------------------- /examples/example/demo/isolate/x04_api_mx_iso.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.isolate.x04-api-mx-iso 2 | (:require 3 | ["package:flutter/gestures.dart" :as g] 4 | ["package:flutter/material.dart" :as m 5 | :refer [Canvas Size]] 6 | ["package:flutter/painting.dart" :as p] 7 | ["package:vector_math/vector_math_64.dart" :as vm] 8 | ["dart:math" :as math 9 | :refer [pi cos sin]] 10 | ["dart:async" :as async 11 | :refer [Completer StreamSubscription]] 12 | ["dart:isolate" :as di 13 | :refer [Isolate SendPort ReceivePort]] 14 | 15 | [tilton.mx.api :as md] 16 | [tilton.mx.cell.base :as cb] 17 | [tilton.mx.api :as mx 18 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 19 | fmu muv fm* mav mx-bound? wmx-iso with-cc]] 20 | [tilton.fmx.api :as fx] 21 | [example.demo.isolate.common :as cmn 22 | :refer [clock-face slow-is-prime? ]])) 23 | 24 | (defn make-app [] 25 | (let [title "MX Iso 4 Clock"] 26 | (fx/material-app 27 | {:title title} 28 | {:name :app 29 | :fact-iso (cF (let [the-app me] 30 | (fx/make-isolate 31 | ;; worker 32 | (fn [{:keys [msg-type of-integer] :as task}] 33 | (case msg-type 34 | :compute-factorial (let [r (atom 1)] 35 | (doseq [i (range 1 (inc of-integer))] (swap! r * i)) 36 | {:of-integer of-integer 37 | :factorial @r}) 38 | (dp :WORKER-UNEXPECTED-TASK!!!!!!!))) 39 | ;; result handler omitted; mx-iso value gets result 40 | )))} 41 | (fx/scaffold 42 | {:appBar (fx/app-bar {:title (fx/text title)}) 43 | :floatingActionButton (fx/floating-action-button 44 | {:onPressed (fx/dart-cb [] 45 | (wmx-iso 46 | (let [fo (fmu :facto-display)] 47 | (dp :bumping-of!!!! (minfo fo)) 48 | (mswap! fo :of + 2)))) 49 | :tooltip "Send msg"})} 50 | (fx/column 51 | {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 52 | (clock-face) 53 | 54 | (fx/text {} 55 | {:name :facto-display 56 | :of (cI 1 :watch (fn [_ me new-val _ _] 57 | (when-let [iso (mav :fact-iso)] 58 | (when-let [tasko (mget iso :task-out-port)] 59 | ; now we have a pipe to the worker, and can send it our one task: 7 60 | (.send ^SendPort tasko 61 | {:msg-type :compute-factorial 62 | :of-integer new-val})))))} 63 | (str "The factorial of " (mget me :of) " ... ")) 64 | (fx/text {} 65 | {:name :mx-iso-display} 66 | (let [mxi (muv :app :fact-iso)] 67 | (str "... is " 68 | (:factorial (mget mxi :value)))))))))) 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /examples/example/demo/navigation/component.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.navigation.component 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | [clojure.string :as str] 6 | [tilton.mx.model.base :refer [md-cell md-install-cell md-awaken]] 7 | [tilton.mx.api :refer [dp minfo cF cFI cF+ cI cFn cFonce mmx-md mget mset! mswap! navig fm* fmu fasc mav] :as mx] 8 | [tilton.fmx.api :as fx 9 | :refer [dart-cb within-ctx 10 | material-app scaffold app-bar floating-action-button 11 | center column row container text-button text sized-box]] 12 | 13 | [example.demo.navigation.puzzle :as pz 14 | :refer [mk-puzzle pz-structure pz-nvg-options]])) 15 | 16 | (defn nvg-solution [] 17 | (column 18 | (m/Text "1. Click to select a starting widget. 2. Enter target name or path. 3. Set options. 4. Click FAB.") 19 | (nvg-what) 20 | (nvg-options))) 21 | 22 | (defn nvg-what [] 23 | (fx/material 24 | {:elevation 6.0 25 | :color m/Colors.white 26 | :shadowColor m/Colors.black} 27 | (fx/intrinsic-width 28 | (fx/text-field {:autofocus true 29 | :focusNode (m/FocusNode) 30 | :decoration (m/InputDecoration 31 | .hintText "Target?" 32 | .border m.InputBorder/none 33 | .contentPadding (m/EdgeInsets.all 9.0)) 34 | :onSubmitted (dart-cb [value] 35 | (let [trimmed (str/trim value)] 36 | (mset! me :value trimmed))) 37 | :controller (cFonce (fx/text-field-controller-basic me))} 38 | {:name :what 39 | :value (cI "")})))) 40 | 41 | (defn nvg-options [] 42 | (row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly 43 | :crossAxisAlignment m/CrossAxisAlignment.start} 44 | (nvg-option :must?) 45 | (nvg-option :me?) 46 | (nvg-option :inside?) 47 | (nvg-option :out) 48 | (nvg-option :out-asc-only) 49 | (nvg-option :dbg))) 50 | 51 | (defn nvg-option [option] 52 | (fx/sized-box {:width 200} 53 | (fx/checkbox-list-tile 54 | {:key (m/ValueKey (name option)) 55 | :controlAffinity m/ListTileControlAffinity.leading 56 | :title (m/Text (name option)) 57 | :value (cF (option (mav :nvg-options))) 58 | :onChanged (dart-cb [on-off] 59 | (mswap! (mav :nvg-options) option not))}))) -------------------------------------------------------------------------------- /examples/example/demo/navigation/puzzle.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.navigation.puzzle 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | [tilton.mx.foundation :refer [PObserver]] 6 | [tilton.mx.model.peek :refer [Model]] 7 | [tilton.mx.model.base :refer [md-cell md-install-cell md-awaken]] 8 | [tilton.mx.api :as mx 9 | :refer [dp minfo cF cFI cF+ cI cFn cFonce mmx-md mget mset! mswap! navig fm* fmu fasc mav 10 | def-mx-props]] 11 | [tilton.fmx.api :as fx 12 | :refer [dart-cb within-ctx 13 | material-app scaffold app-bar floating-action-button 14 | center column row container text-button text sized-box]])) 15 | 16 | ;;; --- domain ----------------------------------- 17 | 18 | (deftype Puzzle [] 19 | :extends Model 20 | PObserver 21 | (observe [this prop me new-value prior-value cell] 22 | #_(dp :hand-sees prop :now new-value))) 23 | 24 | (def-mx-props pz- structure start seek nvg-options) 25 | 26 | (defn mk-puzzle [structure] 27 | (mx/make (Puzzle) 28 | :structure structure 29 | :nvg-options {:me? false :inside? false :out true :out-asc-only false :without-dependency? true :must? true 30 | :dbg false} 31 | :start (cI nil) 32 | :seek (cI nil))) 33 | 34 | ;;; --- puzzles ------------------------------------------- 35 | 36 | (def pzl-zero [[:app {:a 1 :b "2"}] 37 | [[[:scaffy {:c 3 38 | :appBar [:bar {:title "Moby" 39 | :bgColor "red"}]}] 40 | [:body]] :bogus]]) 41 | 42 | #_[:app [:scaffy [[[:app-bar {:p0 42 :p1 "red"}] [:aaa :bbb [:ccc [:dddd :eeee :ffff]]]] 43 | #_#_[:body [[:aa [:aaa]] 44 | [:aa [:aaa]] 45 | :bbb]] 46 | [:drawer [[:aa [:aaa]] 47 | [:aa [:aaa]] 48 | :bbb]] 49 | #_:fab]]] -------------------------------------------------------------------------------- /examples/example/demo/parrot/poetry.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.parrot.poetry 2 | (:require 3 | [clojure.string :as str])) 4 | 5 | (def graves-reproach-s1 6 | (str ;; "\"Reproach\"\n\nby Robert Graves\n\n" 7 | "Your grieving moonlight face looks down\n" 8 | "Through the forest of my fears,\n" 9 | #_#_ "Crowned with a spiny bramble-crown,\n" 10 | "Dew-dropped with evening tears.\n")) 11 | 12 | (def graves-reproach-s2 13 | (str "The black trees shudder, dropping snow,\n" 14 | "The stars tumble and spin.\n" 15 | "Speak, speak, or how may a child know\n" 16 | "His ancestral sin?\n")) 17 | 18 | (def frost-reluctance 19 | (str ;"\"Reluctance\"\n\nby Robert Frost\n\n" 20 | "Ah, when to the heart of man\n" 21 | "Was it ever less than a treason,\n" 22 | "To go with the drift of things,\n" 23 | "To yield with a grace to reason,\n" 24 | "Or acquiesce to the end\n" 25 | "Of a love or a season?\n")) 26 | 27 | (def yeats-second-coming 28 | (str ;"\"The Second Coming\"\nby William Butler Yeats\n\n" 29 | "Turning and turning in the widening gyre\n" 30 | "The falcon cannot hear the falconer;\n" 31 | "Things fall apart; the centre cannot hold;\n" 32 | "Mere anarchy is loosed upon the world.\n")) 33 | 34 | (def graves-jealousy 35 | (str ;"\"Jealousy\"\n\nby Robert Graves\n\n" 36 | "I'd die for you, or you for me, \n" 37 | "So furious is our jealousy-- \n" 38 | "And if you doubt this to be true, \n" 39 | "Kill me outright, lest I kill you.\n")) 40 | 41 | (def carroll-jabberwocky 42 | (str ;"\"Jabberwocky\"\n\nby Lewis Carroll\n\n" 43 | "’Twas brillig, and the slithy toves\n" 44 | "Did gyre and gimble in the wabe:\n" 45 | "All mimsy were the borogoves,\n" 46 | "And the mome raths outgrabe.\n")) 47 | 48 | (def lincoln-gettysburgh 49 | (str ;"\"Gettysburgh Address\n\nAbraham Lincoln\n\n" 50 | ;"The brave men, living and dead,\n" 51 | ;"Who struggled here have consecrated it,\n" 52 | ;"Far above our poor power to add or detract.\n" 53 | "The world will little note,\n" 54 | "Nor long remember what we say here,\n" 55 | "But it can never forget what they did here.\n")) 56 | 57 | (def shakespeare-sonnet-24 58 | (str ;"\"Sonnet 24\"\n\nWilliam Shakespeare\n\n" 59 | "Mine eye hath played the painter\n" 60 | "And hath stell’d thy beauty's form\n" 61 | "In table of my heart.\n")) -------------------------------------------------------------------------------- /examples/example/demo/parrot/stt/common.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.parrot.stt.common 2 | (:require 3 | ["package:speech_to_text/speech_to_text.dart" :as stt])) 4 | 5 | (def ^stt/SpeechToText STT (stt/SpeechToText)) -------------------------------------------------------------------------------- /examples/example/demo/parrot/stt/core.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.parrot.stt.core 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | ["package:flutter/widgets.dart" :as w] 6 | ; 7 | ["package:speech_to_text/speech_to_text.dart" :as stt] 8 | ["package:speech_to_text_platform_interface/speech_to_text_platform_interface.dart" :as sttpi] 9 | ["package:speech_to_text/speech_recognition_error.dart" :as stte] 10 | ["package:speech_to_text/speech_recognition_result.dart" :as sttr] 11 | 12 | [clojure.string :as str] 13 | [tilton.mx.api :as mx 14 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 15 | fmu muv fm* mav mx-bound? wmx-iso]] 16 | [tilton.fmx.api :as fx 17 | :refer [scaffold app-bar text center column hero material-app 18 | container row expanded icon padding opacity ignore-pointer 19 | checkbox-list-tile icon-button fx-render dart-cb]] 20 | [example.demo.parrot.stt.common :as cmn])) 21 | 22 | ; todo: move to mx api 23 | (defmacro try-wmx-iso [& body] 24 | `(try 25 | (tilton.mx.api/wmx-iso ~@body) 26 | (catch Exception e# 27 | (dp :FLUTTERCATCH!! e#)))) 28 | 29 | (defn sp-initializer-rule [] 30 | (cF+ [:async? true 31 | :watch (fn [_ me new _ _] 32 | (dpx :initialized? new) 33 | (when new 34 | (dpx :post-init-avail (.-isAvailable cmn/STT)) 35 | (dpx :post-init-listening (.-isListening cmn/STT)) 36 | (dpx :post-init-has-error (.-hasError cmn/STT)) 37 | (when new 38 | (try-wmx-iso 39 | (mset! me :sp-status :available)))))] 40 | (.initialize cmn/STT 41 | .onStatus (fn [status] 42 | (try-wmx-iso 43 | (dp :onStatus-sets-status (keyword status)) 44 | (mset! me :sp-status (keyword status)))) 45 | .onError (fn [^stte/SpeechRecognitionError err] 46 | (dp :sp-error!!!!! (.-errorMsg err)) 47 | (try-wmx-iso 48 | (mset! me :transcript (str "Error: " (.-errorMsg err)))))))) 49 | 50 | (defn stop-listening [me] 51 | (dpx :requesting-stop) 52 | (.stop cmn/STT)) 53 | 54 | 55 | -------------------------------------------------------------------------------- /examples/example/demo/todoMVC/common.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.todoMVC.common 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | [tilton.mx.base :refer [dprn dp dpx]])) 5 | 6 | (defn title-red [] 7 | (.fromRGBO m/Color 184 63 69 0.5)) 8 | 9 | (defmacro my-todo-list [] 10 | `(tilton.mx.model.base/mget 11 | (tilton.mx.model.core/fasc :app) 12 | :todo-list)) -------------------------------------------------------------------------------- /examples/example/demo/todoMVC/persist.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.todoMVC.persist 2 | (:require 3 | ["package:hive_flutter/hive_flutter.dart" :as hv] 4 | ["dart:convert" :as convert] 5 | ["package:uuid/uuid.dart" :as uu] 6 | [tilton.mx.util :as util] 7 | [clojure.walk :as walk])) 8 | 9 | (def +DB+ (atom nil)) ;; n.b. just a cache, NOT reactive 10 | (defn ^hv/Box? DB [] (deref +DB+)) 11 | (defn ^hv/Box? DB! [db] (reset! +DB+ db)) 12 | 13 | (def +uuid+ (atom nil)) 14 | (defn ^uu/Uuid UUID [] 15 | (or (deref +uuid+) 16 | (uu/Uuid))) 17 | 18 | (defn td-store 19 | "Write a CLJD ToDo map to persistent storage. 20 | Map must contain :stg-id, a string identifier. 21 | Returns the stg-id." 22 | [td-map] 23 | (let [stg-id (:stg-id td-map)] 24 | (assert stg-id "td-rewrite map must include stg-id") 25 | (.put (DB) stg-id 26 | (convert/jsonEncode 27 | (walk/stringify-keys 28 | (select-keys td-map 29 | [:stg-id :created-at :title :completed])))) 30 | stg-id)) 31 | 32 | (defn td-initialize 33 | "Create a Hive to-do from a CLJD map alone. 34 | Returns the unique storage key generated for the data." 35 | [collection-name td-map] 36 | (when-let [stg-id (:stg-id td-map)] 37 | (throw (Exception. (str "td-initialize> sees :stg-id " stg-id ", suggesting td already written")))) 38 | 39 | (let [new-stg-id (str collection-name "/" (.v4 (UUID)))] 40 | (td-store 41 | (assoc td-map :stg-id new-stg-id)) 42 | new-stg-id)) 43 | 44 | (defn td-rewrite 45 | "Update a stored to-do given only a CLJD map of its properties. 46 | Map must contain non-nil :stg-id." 47 | [td-map] 48 | (assert (:stg-id td-map) 49 | "td-rewrite> map must include stg-id") 50 | (td-store td-map) 51 | (:stg-id td-map)) 52 | 53 | (defn td-delete 54 | "Deletes storage associated with stg-id." 55 | [stg-id] 56 | (assert stg-id "td-delete> stg-id argument is nil. s/b string ID.") 57 | (.delete (DB) stg-id) 58 | stg-id) 59 | 60 | ;;; --- collection-level utilities ------------- 61 | 62 | (defn collection-docs [collection-name] 63 | (let [all-td-keys (collection-keys collection-name)] 64 | (mapv (fn [td-key] 65 | (util/dart-map->cljd-map 66 | (convert/jsonDecode (.get (DB) td-key)))) 67 | all-td-keys))) 68 | 69 | (defn collection-keys [collection-name] 70 | (into #{} (.-keys (DB)))) 71 | 72 | (defn collection-delete-all [collection-name] 73 | (doseq [k (collection-keys collection-name)] 74 | (td-delete k))) -------------------------------------------------------------------------------- /examples/example/demo/todoMVX/README.md: -------------------------------------------------------------------------------- 1 | # TodoMVX: TodoMVC via Flutter, ColureDart, Matrix, and Supabase 2 | 3 | Programming [Flutter](https://flutter.dev/?gclid=CjwKCAjwwdWVBhA4EiwAjcYJEEoxUuE14sd2MGLJW35qeuJynmTRjqpUL3SbIUhOiS4TihjyZ9iTVRoCJkoQAvD_BwE&gclsrc=aw.ds) with [ClojureDart](https://github.com/Tensegritics/ClojureDart), [Matrix](https://github.com/kennytilton/matrix), a generic, fine-grained, transparent, reactive state manager, and Supabase. 4 | 5 | #### PREREQUISITES 6 | 7 | To run this example, we have to: 8 | 1. create a free account on Supabase; 9 | 2. define a project called "to-do"; 10 | 3. create a table for to-dos: 11 | ```postgresql 12 | -- Table: public.to-do 13 | 14 | -- DROP TABLE IF EXISTS public."to-do"; 15 | 16 | CREATE TABLE IF NOT EXISTS public."to-do" 17 | ( 18 | created_at timestamp with time zone NOT NULL DEFAULT now(), 19 | title text COLLATE pg_catalog."default" NOT NULL, 20 | due_by timestamp with time zone, 21 | completed boolean NOT NULL DEFAULT false, 22 | uid uuid NOT NULL DEFAULT gen_random_uuid(), 23 | CONSTRAINT "to-do_pkey" PRIMARY KEY (uid), 24 | CONSTRAINT "to-do_uid_key" UNIQUE (uid) 25 | ) 26 | 27 | TABLESPACE pg_default; 28 | 29 | ALTER TABLE IF EXISTS public."to-do" 30 | OWNER to postgres; 31 | 32 | GRANT ALL ON TABLE public."to-do" TO anon; 33 | 34 | GRANT ALL ON TABLE public."to-do" TO authenticated; 35 | 36 | GRANT ALL ON TABLE public."to-do" TO postgres; 37 | 38 | GRANT ALL ON TABLE public."to-do" TO service_role; 39 | 40 | COMMENT ON TABLE public."to-do" 41 | IS 'TodoMVC Classic'; 42 | ``` 43 | 3. get the project URL and secret key and create nvars in your login script: 44 | * `export SUPA_MVX_URL=""` 45 | * `export SUPA_MVX_KEY=""` 46 | 4. run like this, a bash script easiest: 47 | ``` bash 48 | clj -M:cljd flutter --dart-define=SUPA_MVX_URL=$SUPA_MVX_URL \ 49 | --dart-define=SUPA_MVX_KEY=$SUPA_MVX_KEY 50 | ``` 51 | 5. add `-d chrome` to run on the web; and 52 | 6. Finally, certain entitlements are required to access Supabase via HTTP Edit the `Runnner>Runner>DebugProfile` and edit `Entitlements file`, adding: 53 | * com.apple.security.network.server 54 | 7. Do the same with `R>R>Release` if one is planned. 55 | 56 | 57 | Ping @kennytilton on #clojurians Slack for help! 58 | -------------------------------------------------------------------------------- /examples/example/demo/todoMVX/common.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.todoMVX.common 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | [tilton.mx.base :refer [dprn dp dpx]] 5 | [tilton.mx.api :as mx])) 6 | 7 | (defn title-red [] 8 | (.fromRGBO m/Color 184 63 69 0.5)) 9 | 10 | 11 | (defn app-now [] 12 | (mx/now-ms)) 13 | 14 | (defn app-now-utc [] 15 | (.toString (.fromMillisecondsSinceEpoch DateTime (app-now) 16 | .isUtc true))) 17 | 18 | 19 | (defmacro my-todo-list [& [me]] 20 | `(let [me# ~(or me 'me)] 21 | (tilton.mx.model.base/mget 22 | (tilton.mx.model.core/fasc :app me#) 23 | :todo-list))) 24 | 25 | (defmacro my-todos [] 26 | `(tilton.mx.api/mkids (example.demo.todoMVX.common/my-todo-list))) 27 | 28 | (defmacro my-todo-add [title] 29 | `(let [list# (example.demo.todoMVX.common/my-todo-list)] 30 | (tilton.mx.api/mswap! list# :kids conj 31 | (example.demo.todoMVX.common/make-ToDo list# 32 | ~title)))) -------------------------------------------------------------------------------- /examples/example/demo/todoMVX/persist.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.todoMVX.persist 2 | (:require 3 | ["package:hive_flutter/hive_flutter.dart" :as hv] 4 | ["dart:convert" :as convert] 5 | ["package:uuid/uuid.dart" :as uu] 6 | [tilton.mx.util :as util] 7 | [clojure.walk :as walk])) 8 | 9 | (def +DB+ (atom nil)) ;; n.b. just a cache, NOT reactive 10 | (defn ^hv/Box? DB [] (deref +DB+)) 11 | (defn ^hv/Box? DB! [db] (reset! +DB+ db)) 12 | 13 | (def +uuid+ (atom nil)) 14 | (defn ^uu/Uuid UUID [] 15 | (or (deref +uuid+) 16 | (uu/Uuid))) 17 | 18 | (defn td-store 19 | [td-map] 20 | (let [uid (:uid td-map)] 21 | (assert uid "td-rewrite map must include uid") 22 | (.put (DB) uid 23 | (convert/jsonEncode 24 | (walk/stringify-keys 25 | (select-keys td-map 26 | [:uid :created-at :title :completed])))) 27 | uid)) 28 | 29 | (defn td-initialize 30 | "Create a Hive to-do from a CLJD map alone. 31 | Returns the unique storage key generated for the data." 32 | [collection-name td-map] 33 | (when-let [uid (:uid td-map)] 34 | (throw (Exception. (str "td-initialize> sees :uid " uid ", suggesting td already written")))) 35 | 36 | (let [new-uid (str collection-name "/" (.v4 (UUID)))] 37 | (td-store 38 | (assoc td-map :uid new-uid)) 39 | new-uid)) 40 | 41 | (defn td-rewrite 42 | "Update a stored to-do given only a CLJD map of its properties. 43 | Map must contain non-nil :uid." 44 | [td-map] 45 | (assert (:uid td-map) 46 | "td-rewrite> map must include uid") 47 | (td-store td-map) 48 | (:uid td-map)) 49 | 50 | (defn td-delete 51 | "Deletes storage associated with uid." 52 | [uid] 53 | (assert uid "td-delete> uid argument is nil. s/b string ID.") 54 | (.delete (DB) uid) 55 | uid) 56 | 57 | ;;; --- collection-level utilities ------------- 58 | 59 | (defn collection-docs [collection-name] 60 | (let [all-td-keys (collection-keys collection-name)] 61 | (mapv (fn [td-key] 62 | (util/dart-map->cljd-map 63 | (convert/jsonDecode (.get (DB) td-key)))) 64 | all-td-keys))) 65 | 66 | (defn collection-keys [collection-name] 67 | (into #{} (.-keys (DB)))) 68 | 69 | (defn collection-delete-all [collection-name] 70 | (doseq [k (collection-keys collection-name)] 71 | (td-delete k))) -------------------------------------------------------------------------------- /examples/example/demo/todoMVX/supa.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.todoMVX.supa 2 | (:require 3 | ["dart:convert" :as convert] 4 | ["package:uuid/uuid.dart" :as uu] 5 | ["package:supabase_flutter/supabase_flutter.dart" :as supabase] 6 | [tilton.mx.api :as mx 7 | :refer [dp dpx mget mget? mset! mswap! fasc cF cF+ cI]] 8 | [clojure.string :as str])) 9 | 10 | 11 | (defn stg-upsert [table table-props me] ;; a model, such as light from make-Light 12 | (dpx :STGupsert-sees table-props (mget? me :created_at)(mget? me :created-at)) 13 | (let [op (-> supabase/Supabase.instance.client 14 | (.from table) 15 | (.upsert (into {} (for [prop table-props] 16 | [(str/replace (name prop) #"-" "_") 17 | (mget me prop)]))))] 18 | (dpx :upsert!!!!! op (dart/is? op Future)) 19 | (await op) ;; effects the write 20 | (mget me :uid))) 21 | 22 | (defn stg-rewrite [table table-props me] ;; a model, such as light from make-Light 23 | (dpx :stg-rewriting (mx/minfo me)) 24 | (stg-upsert table table-props me) 25 | (mget me :uid)) 26 | 27 | (defn stg-insert [table table-props props] ;; a model, such as light from make-Light 28 | (dp :STGINSERT-entry table table-props props) 29 | (let [row (into {} (for [prop table-props] 30 | [(str/replace (name prop) #"-" "_") ;; can't hurt if we never force hyphens on pg 31 | (get props prop)]))] 32 | ;(dp :STGIN-ACTUAL-row table row) 33 | (let [fop (-> supabase/Supabase.instance.client 34 | (.from table) 35 | (.insert row) 36 | .select)] 37 | (let [props (atom (await fop))] 38 | (deref props))))) 39 | 40 | (defn stg-delete 41 | "Deletes storage associated with uid." 42 | [table uid] 43 | (assert uid (str "stg-delete> " table " uid argument is nil. s/b string ID.")) 44 | (let [op (-> supabase/Supabase.instance.client 45 | (.from table) 46 | .delete 47 | (.match {"uid" uid}))] 48 | (await op) 49 | uid)) -------------------------------------------------------------------------------- /examples/example/demo/todoMVX/todoMVX.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/examples/example/demo/todoMVX/todoMVX.sql -------------------------------------------------------------------------------- /examples/example/demo/tts/core.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.tts.core 2 | "Originally, a straught port of the `flutter_tts` package example https://github.com/dlutton/flutter_tts/blob/master/example/lib/main.dart" 3 | (:require 4 | ["package:flutter/material.dart" :as m] 5 | ["package:flutter/painting.dart" :as p] 6 | ["package:flutter_tts/flutter_tts.dart" :as fts 7 | :refer [FlutterTts]] 8 | ["package:flutter/widgets.dart" :as w] 9 | [clojure.string :as str] 10 | [tilton.mx.api :as mx 11 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 12 | fmu muv fm* mav mx-bound? wmx-iso]] 13 | [tilton.fmx.api :as fx 14 | :refer [scaffold app-bar text center column hero material-app 15 | container row expanded icon padding opacity ignore-pointer 16 | checkbox-list-tile icon-button fx-render dart-cb]] 17 | [example.demo.tts.fts :as fts 18 | :refer [app-fts-progress app-fts-status]] 19 | [example.demo.tts.component 20 | :refer [lang-chooser geo-chooser voice-chooser play-pause-button stop-button auto-play 21 | equalizer choice-header]] 22 | [example.demo.tts.poetry :as poetry])) 23 | 24 | ;;; === app ====================================================== 25 | (declare dashboard speech-input) 26 | 27 | (defn chyron [] 28 | (container 29 | {:padding (m/EdgeInsets.symmetric .horizontal 16.0)} 30 | (fx/text {:textAlign m/TextAlign.center} 31 | {:phrase (cF+ [:sst nil] 32 | (when (not= :off (app-fts-status)) 33 | (let [{:keys [word]} (app-fts-progress)] 34 | (if (nil? word) [] 35 | (take-last 5 36 | (concat (if (mx-bound? _cache) _cache []) 37 | [word]))))))} 38 | (str/join "..." (mget me :phrase))))) 39 | 40 | (defn make-app [] 41 | (material-app {} 42 | {:name :app 43 | :fts (cF (fts/make-flutter-tts))} 44 | (scaffold 45 | {:appBar (app-bar {:title (m/Text "Flutter TTS Demo")})} 46 | (column 47 | {:crossAxisAlignment m/CrossAxisAlignment.stretch} 48 | (choice-header "Languages") 49 | (lang-chooser) 50 | (choice-header "Geography") 51 | (geo-chooser) 52 | (choice-header "Voices") 53 | (voice-chooser) 54 | (choice-header "Script") 55 | (speech-input poetry/graves-jealousy) 56 | (chyron) 57 | (dashboard) 58 | (auto-play) 59 | (equalizer))))) 60 | 61 | ;;; --- dashboard --------------------------------------------------------------- 62 | 63 | (defn dashboard [] 64 | (container {:padding (m/EdgeInsets.only .top 8 .bottom 8)} 65 | (row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 66 | (play-pause-button) 67 | (stop-button)))) 68 | 69 | ;;; --- text input -------------------------------------------------------------- 70 | 71 | (defn speech-input [speech-initial] 72 | (container 73 | {:alignment m/Alignment.topCenter 74 | :padding (m/EdgeInsets.only 75 | .top 25.0 .left 25.0 .right 25.0 .bottom 9)} 76 | (fx/text-field 77 | {:style (p/TextStyle 78 | .fontFamily "Helvetica Neue" 79 | .fontSize 20.0) 80 | :controller (cFonce 81 | (m/TextEditingController .text (mget me :value))) 82 | :onChanged (dart-cb [text] 83 | (mset! me :value text)) 84 | :minLines 6 :maxLines 11} 85 | {:name :text-in 86 | :value (cI speech-initial)}))) 87 | 88 | -------------------------------------------------------------------------------- /examples/example/demo/tts/poetry.cljd: -------------------------------------------------------------------------------- 1 | (ns example.demo.tts.poetry 2 | (:require 3 | [clojure.string :as str])) 4 | 5 | (def graves-reproach-s1 6 | (str ;; "\"Reproach\"\n\nby Robert Graves\n\n" 7 | ;"Your grieving moonlight face looks down\n" 8 | "Through the forest of my fears,\n" 9 | "Crowned with a spiny bramble-crown,\n" 10 | "Dew-dropped with evening tears.\n")) 11 | 12 | (def graves-reproach-s2 13 | (str "The black trees shudder, dropping snow,\n" 14 | "The stars tumble and spin.\n" 15 | "Speak, speak, or how may a child know\n" 16 | "His ancestral sin?\n")) 17 | 18 | (def frost-reluctance 19 | (str ;"\"Reluctance\"\n\nby Robert Frost\n\n" 20 | "Ah, when to the heart of man\n" 21 | "Was it ever less than a treason,\n" 22 | "To go with the drift of things,\n" 23 | "To yield with a grace to reason,\n" 24 | "Or acquiesce to the end\n" 25 | "Of a love or a season?\n")) 26 | 27 | (def yeats-second-coming 28 | (str ;"\"The Second Coming\"\nby William Butler Yeats\n\n" 29 | "Turning and turning in the widening gyre\n" 30 | "The falcon cannot hear the falconer;\n" 31 | "Things fall apart; the centre cannot hold;\n" 32 | "Mere anarchy is loosed upon the world.\n")) 33 | 34 | (def graves-jealousy 35 | (str ;"\"Jealousy\"\n\nby Robert Graves\n\n" 36 | "I'd die for you, or you for me, \n" 37 | "So furious is our jealousy-- \n" 38 | "And if you doubt this to be true, \n" 39 | "Kill me outright, lest I kill you.\n")) 40 | 41 | (def carroll-jabberwocky 42 | (str ;"\"Jabberwocky\"\n\nby Lewis Carroll\n\n" 43 | "’Twas brillig, and the slithy toves\n" 44 | "Did gyre and gimble in the wabe:\n" 45 | "All mimsy were the borogoves,\n" 46 | "And the mome raths outgrabe.\n")) 47 | 48 | (def lincoln-gettysburgh 49 | (str ;"\"Gettysburgh Address\n\nAbraham Lincoln\n\n" 50 | ;"The brave men, living and dead,\n" 51 | ;"Who struggled here have consecrated it,\n" 52 | ;"Far above our poor power to add or detract.\n" 53 | "The world will little note,\n" 54 | "Nor long remember what we say here,\n" 55 | "But it can never forget what they did here.\n")) 56 | 57 | (def shakespeare-sonnet-24 58 | (str ;"\"Sonnet 24\"\n\nWilliam Shakespeare\n\n" 59 | "Mine eye hath played the painter\n" 60 | "And hath stell’d thy beauty's form\n" 61 | "In table of my heart.\n")) -------------------------------------------------------------------------------- /examples/example/eg/flutter_layout_tutorial.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.flutter-layout-tutorial 2 | "Port of Dave Liepmann's ClojureDart port https://github.com/daveliepmann/ClojureDart/tree/main/samples/flutter_tutorial_building_layouts 3 | of Flutter 'Building layouts' tutorial https://docs.flutter.dev/ui/layout/tutorial" 4 | (:require 5 | ["package:flutter/material.dart" :as m] 6 | ["package:flutter/painting.dart" :as p] 7 | [clojure.string :as str] 8 | [tilton.mx.api :refer [ dp dpx cF cF+ cI mget mswap! mset! mav fasc fm* muv fmu minfo] :as mx] 9 | [tilton.fmx.api :as fx 10 | :refer [scaffold app-bar text center column hero material-app 11 | container row expanded icon padding within-ctx]])) 12 | 13 | (defn make-app [] 14 | (let [title "Flutter layout demo (cljd-ified!)"] 15 | (material-app 16 | {:title title} 17 | (scaffold 18 | {:appBar (app-bar {:title (text title)})} 19 | (column 20 | (m/Image.asset "image/lake-oeschinen.jpeg" 21 | .width 600 .height 240 22 | .fit m/BoxFit.cover) 23 | 24 | (title-section) 25 | 26 | (fx/builder ;; supplies extra context to support Theme.of 27 | (row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 28 | (into [] (for [[ico label] [[m/Icons.call "CALL"] 29 | [m/Icons.near_me "ROUTE"] 30 | [m/Icons.share "SHARE"]]] 31 | (button-column (within-ctx [me ctx] 32 | (.-primaryColor (m/Theme.of ctx))) 33 | ico label))))) 34 | 35 | (padding {:padding (m/EdgeInsets.all 32)} 36 | (text {:softWrap true} 37 | (campground-desc)))))))) 38 | 39 | ;;; --- sections ------------------------------------------------------ 40 | 41 | (defn title-section [] 42 | (container 43 | {:padding (m/EdgeInsets.all 32)} 44 | (row 45 | (expanded 46 | (column {:crossAxisAlignment m/CrossAxisAlignment.start} 47 | (container {:padding (m/EdgeInsets.only .bottom 8)} 48 | (text {:style (m/TextStyle .fontWeight m/FontWeight.bold)} 49 | "Oeschinen Lake Campground")) 50 | (text {:style (m/TextStyle .color (m/Colors.grey 500))} 51 | "Kandersteg, Switzerland"))) 52 | (fx/icon {:color (m/Colors.red 500)} 53 | m/Icons.star) 54 | (text "41")))) 55 | 56 | (defn button-column [color icon label] 57 | (column {:mainAxisSize m/MainAxisSize.min 58 | :mainAxisAlignment m/MainAxisAlignment.center} 59 | {:name :button-col} 60 | (fx/icon {:color color} icon) 61 | (container {:margin (m/EdgeInsets.only .top 8)} 62 | (text {:style (fx/text-style {:fontSize 12 63 | :fontWeight m/FontWeight.w400 64 | :color color})} 65 | label)))) 66 | 67 | (defn campground-desc [] 68 | (str/replace 69 | "Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. 70 | Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. 71 | A gondola ride from Kandersteg, followed by a half-hour walk through pastures 72 | and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. 73 | Activities enjoyed here include rowing, and riding the summer toboggan run." 74 | #"\n" "")) 75 | 76 | -------------------------------------------------------------------------------- /examples/example/eg/x00_hello_world.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x00-hello-world 2 | (:require 3 | [clojure.string :as str] 4 | [tilton.mx.api :refer [cF mget mset! mswap!] :as md] 5 | [tilton.fmx.factory :refer [deftag] :as fxf] 6 | [tilton.fmx.api :as fx 7 | :refer [scaffold app-bar text center column hero material-app]] 8 | ["package:flutter/widgets.dart" :as w] 9 | ["package:flutter/material.dart" :as m] 10 | ["package:flutter/painting.dart" :as p])) 11 | 12 | (deftag fxf/non-widget theme-data m/ThemeData) 13 | (deftag fxf/kidless-childless image w/Image ) 14 | 15 | ;(deftag fxf/kidless-childless asset-image p/AssetImage ) 16 | ; no, this has to be konly-param0 or sth 17 | 18 | (defn make-app [] 19 | (material-app 20 | {:title "Flutter/MX Hello Teal World" 21 | :theme (cF (theme-data 22 | {:primarySwatch (let [ttl (mget me :title)] 23 | ;; silly derivation 24 | (cond 25 | (str/includes? ttl "Teal") m/Colors.teal 26 | (str/includes? ttl "Red") m/Colors.red 27 | :else m/Colors.blue))}))} 28 | (scaffold 29 | {:appBar (app-bar 30 | {:title (m/Text "Welcome to Flutter/MX")})} 31 | (center 32 | (column 33 | {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 34 | (text {:overflow p.TextOverflow/ellipsis 35 | :style (fx/text-style {:fontSize 40 36 | :fontWeight m/FontWeight.w600 37 | :color m/Colors.blue})} 38 | "hello, world\\n") 39 | (hero {:tag "imageHero"} 40 | (image {:image (m/AssetImage "image/kernighan.jpeg") 41 | :height 512})) 42 | (text {:overflow p.TextOverflow/ellipsis 43 | :style (fx/text-style {:fontSize 20 44 | :fontWeight m/FontWeight.w400 45 | :color m/Colors.blue})} 46 | "Brian Kernighan")))))) -------------------------------------------------------------------------------- /examples/example/eg/x01_counter.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x01-counter 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/painting.dart" :as p] 5 | [tilton.mx.model.base :refer [md-cell md-install-cell md-awaken]] 6 | [tilton.mx.api :refer [dp minfo cF cF+ cI cFn cFonce mmx-md mget mset! mswap! fm* fmu fasc mav] :as mx] 7 | [tilton.fmx.api :as fx 8 | :refer [dart-cb within-ctx 9 | material-app scaffold app-bar floating-action-button 10 | center column text sized-box]])) 11 | 12 | (defn make-app [] 13 | (material-app 14 | {:title "Flutter/MX Counter Demo" 15 | :theme (m/ThemeData .useMaterial3 true 16 | .colorScheme (m/ColorScheme.fromSeed 17 | .seedColor m/Colors.deepPurple))} 18 | (scaffold 19 | {:appBar (app-bar 20 | {:title (m/Text "Flutter/MX Counter") 21 | :backgroundColor (cF (.-inversePrimary 22 | (.-colorScheme ^m/ThemeData (mav :theme))))}) 23 | :floatingActionButton (floating-action-button 24 | {:onPressed (dart-cb [] 25 | (mswap! (fm* :counter) :value inc)) 26 | :tooltip "Increment"} 27 | (m/Icon m/Icons.add .color m/Colors.black))} 28 | (center 29 | (column {:mainAxisAlignment m/MainAxisAlignment.center} 30 | (text {:style (-> (m/Theme.of (fx/*ctx)) .-textTheme .-displaySmall) 31 | ;;; this silliness is a test to see if the engine can propagate to setState 32 | ;; when the reactivity is embedded in a delegate model, the text-style. So far so good. 33 | ;; If it fails, try just wrapping the non-updating widget in `(fx/stateful-builder....)` 34 | #_(cF (fx/text-style 35 | {:color m/Colors.black 36 | :fontSize (cF (+ 24.0 (* 1.0 (mget (fm* :counter) :value))))}))} 37 | "Button push count:") 38 | (sized-box 39 | {:height 28.0}) 40 | (text 41 | {:style (-> (m/Theme.of (fx/*ctx)) .-textTheme .-displayMedium)} 42 | {:name :counter 43 | :value (cI 0)} 44 | (str (mget me :value)))))))) 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/example/eg/x01_counter_desugared.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x01-counter-desugared 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | [tilton.mx.api :refer [dp dpx minfo mmx-md cI cF mget mswap! fm* fasc] :as mx] 5 | [tilton.fmx.factory :refer [deftag deftags] :as fxf] 6 | [tilton.fmx.api :as fx 7 | :refer [dart-cb within-ctx 8 | app-bar floating-action-button 9 | theme icon-theme center column text sized-box]])) 10 | 11 | ;;; --- The Flutter Classic: A Counter App ----------------------- 12 | ;;; A straight transliteration from the Dart example Counter app 13 | ;;; 14 | ;;; Note that, unlike the Dart original, this is not one big widget. 15 | ;;; Each different widget below has its own build method and responds 16 | ;;; to a different setState. 17 | 18 | ;;; Here we override the usual sugared widgets that take common 19 | ;;; attributes such as :home and :body from a solo (implicit) child 20 | ;;; with widgets that work closer to the Flutter, and make the properties explicit. 21 | 22 | (deftags tilton.fmx.factory/kidless-childless 23 | (material-app m/MaterialApp) 24 | (scaffold m/Scaffold)) 25 | 26 | (defn make-app [] 27 | (material-app 28 | {:title "Flutter/MX Counter Demo" 29 | :theme (m/ThemeData 30 | .colorScheme (m/ColorScheme.fromSeed 31 | .seedColor m/Colors.deepPurple) 32 | .useMaterial3 true) 33 | :home (cF (scaffold 34 | {:appBar (app-bar {:backgroundColor (fx/within-ctx [me ctx] 35 | (.-inversePrimary (.-colorScheme (m/Theme.of ctx)))) 36 | :title (m/Text "Flutter/MX Counter Classic")}) 37 | :body (cF (center 38 | (column {:mainAxisAlignment m/MainAxisAlignment.center} 39 | (text "You have pushed the button this many times:") 40 | (text 41 | {:style (within-ctx [me ctx] 42 | (.-headlineMedium (.-textTheme (m/Theme.of ctx))))} 43 | (str (mget (fm* :scaffo) :counter)))))) 44 | :floatingActionButton (floating-action-button 45 | {:onPressed (dart-cb [] 46 | (mswap! (fm* :scaffo) :counter inc)) 47 | :tooltip "Increment"} 48 | (m/Icon m/Icons.add))} 49 | {:name :scaffo 50 | :counter (cI 0)}))})) -------------------------------------------------------------------------------- /examples/example/eg/x029_layout_builder.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x029-layout-builder 2 | (:require 3 | ["dart:math" :as math] 4 | ["package:flutter/widgets.dart" :as w] 5 | ["package:flutter/material.dart" :as m] 6 | ["package:flutter/painting.dart" :as p] 7 | [tilton.mx.api :refer [dp cF cI mget muv] :as mx] 8 | [tilton.fmx.factory :refer [binding-ctx]] 9 | [tilton.fmx.api :refer [within-ctx dart-cb] :as fx])) 10 | 11 | (defn make-app [] 12 | (let [title "Layout Builder Dynamic Text Size?"] 13 | (dp :builder-app!! ) 14 | (fx/material-app {:title title} 15 | (fx/scaffold 16 | {:appBar (fx/app-bar {:title (fx/text title)})} 17 | (fx/center 18 | (fx/layout-builder 19 | {:builder (fn [ctx box-constraint] 20 | ;; next bit is key: the layout builder wants back a native Flutter 21 | ;; widget, so we have to do the conversion from f/mx proxy to Flutter 22 | ;; ourselves, sth normally midden by f/mx macrology. 23 | 24 | ;; KNOWN BUG: 25 | (dp :builder-runz!! box-constraint) 26 | ;; above output shows repeated rotation does not invoke builder going 27 | ;; from one horizontal (not sure how to define it) to one portait orientation, 28 | ;; so layout does not get rebuilt. 29 | 30 | (binding-ctx :xo2p-builder-exp ctx 31 | (fx/fx-render ctx 32 | ; now we can play in f/mx world.... 33 | 34 | (fx/column 35 | (let [height (.-height (.-size (m/MediaQuery.of ctx)))] 36 | ;(dp :x029b-sees-height :mq-height height :ctx (fx/*ctx)) 37 | (when (> height 600) 38 | (fx/text 39 | {:style (p/TextStyle 40 | .color m/Colors.blue 41 | .fontSize 24)} 42 | {:name :test} 43 | "Rotate the device or sim to see layout effect."))) 44 | (fx/text 45 | {:style (cF (p/TextStyle 46 | .color (mget me :font-color) 47 | .fontSize (mget me :font-size)))} 48 | {:font-size (* 0.1 (.-maxHeight ^m/BoxConstraints box-constraint)) 49 | :font-color (cF (cond 50 | (> (mget me :font-size) 50) m/Colors.red 51 | :else m/Colors.cyan))} 52 | (str "Fontsize " (/ (int (* 10 (mget me :font-size))) 10))) 53 | (fx/text-field {:controller (m/TextEditingController 54 | .text "Hi, Mom.")} 55 | {:name :test-input})))))})))))) -------------------------------------------------------------------------------- /examples/example/eg/x02_two_counters_ala_flux.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x02-two-counters-ala-flux 2 | "In response to a challenge, we show what it would be like to have 3 | a single map serving as a store, a la Flux." 4 | (:require 5 | [clojure.string :as str] 6 | [tilton.mx.api :refer [dp minfo mav fasc cF cI mget mset! mswap!]] 7 | [tilton.fmx.api :as fx] 8 | 9 | ["package:flutter/widgets.dart" 10 | :refer [Text State StatefulWidget StatelessWidget]] 11 | ["package:flutter/material.dart" :as m 12 | :refer [MainAxisAlignment Colors Theme Icon Icons ThemeData runApp AppBar State]] 13 | ["package:flutter/painting.dart" 14 | :refer [TextStyle]])) 15 | 16 | (defn build-counter [counter-key] 17 | (fx/expanded 18 | (fx/column 19 | {:mainAxisAlignment MainAxisAlignment/center} 20 | {:name counter-key 21 | :counter (cF (get-in (mav :flux-store) [:counters counter-key]))} 22 | (fx/text (str/capitalize (name counter-key))) 23 | (fx/text {:style (TextStyle 24 | .color m/Colors.cyan 25 | .fontSize 32.0)} 26 | {:name :ctr-text} 27 | (str (mav :counter))) 28 | (fx/elevated-button 29 | {:onPressed (fx/dart-cb [] 30 | (mswap! (fasc :counter-app) 31 | :flux-store update-in [:counters counter-key] inc))} 32 | (fx/text "+"))))) 33 | 34 | (defn make-app [] 35 | (fx/material-app 36 | {:title "Two Counters" 37 | :theme (cF (ThemeData .primarySwatch Colors/blue))} 38 | {:name :counter-app 39 | ; simulating a separate global store a la Flux, we bind a purely independent Matrix data structure that 40 | ; must be consulted for values. Pro tip: use `mswap! :flux-store update-in etc` to 41 | ; increment either counter. 42 | :flux-store (cI {:counters {:left 0 :right 0}})} 43 | 44 | (fx/scaffold 45 | {:appBar (fx/app-bar {:title (fx/text "Two Counters ala Flux")})} 46 | (fx/center 47 | (fx/row 48 | {:mainAxisAlignment MainAxisAlignment/center} 49 | (mapv #(build-counter %) [:left :right])))))) -------------------------------------------------------------------------------- /examples/example/eg/x02_two_counters_ala_matrix.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x02-two-counters-ala-matrix 2 | (:require 3 | ["package:flutter/widgets.dart" 4 | :refer [Text State StatefulWidget StatelessWidget]] 5 | ["package:flutter/material.dart" :as m 6 | :refer [MainAxisAlignment Colors Theme Icon Icons ThemeData runApp AppBar State]] 7 | ["package:flutter/painting.dart" 8 | :refer [TextStyle]] 9 | 10 | [clojure.string :as str] 11 | [tilton.mx.api :refer [cF cI make mget cFkids fmu muv] :as mx] 12 | [tilton.fmx.api :as fx] 13 | )) 14 | 15 | (defn- build-counter [counter-key] 16 | (fx/expanded 17 | (fx/column 18 | {:mainAxisAlignment MainAxisAlignment/center} 19 | {:name :ctr-col 20 | ;; The column maintains its own state, aka "in-place state". 21 | ;; We find it useful to give every widget a "value" property for holding the primary value of a widget 22 | :value (cI 0)} 23 | (fx/text (str/capitalize (name counter-key))) 24 | (fx/text {:style (fx/within-ctx [me ctx] 25 | (-> (Theme/of ctx) .-textTheme .-displayLarge))} 26 | (str (mx/muv :ctr-col))) 27 | (fx/elevated-button 28 | {:onPressed (fn ^void [] 29 | (mx/mswap! (mx/fm* :ctr-col) :value inc))} 30 | (fx/text "+"))))) 31 | 32 | (defn make-app [] 33 | (fx/material-app {:title "Two Counters (MX)" 34 | :theme (cF (ThemeData .primarySwatch Colors/blue))} 35 | (fx/scaffold 36 | {:appBar (AppBar .title (Text "Two Counters (MX)"))} 37 | (fx/center 38 | (fx/row 39 | {:mainAxisAlignment MainAxisAlignment/center} 40 | (mapv #(build-counter %) 41 | [:left :right])))))) -------------------------------------------------------------------------------- /examples/example/eg/x040_named_routes.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x040-named-routes 2 | "Port of CLJD sample.navigate-named-routes... 3 | Port of https://docs.flutter.dev/cookbook/navigation/named-routes.html" 4 | (:require 5 | [tilton.fmx.api :as fx 6 | :refer [dart-cb scaffold app-bar elevated-button text center material-app ]] 7 | ["package:flutter/material.dart" :as m])) 8 | 9 | ;; KNOWN BUG: Coming into this example on hot reload after a different example was running 10 | ;; fails in builder on "Null check operator used on a null value" 11 | 12 | (defn first-screen [ctx] 13 | (scaffold 14 | {:appBar (app-bar 15 | {:title (m/Text "First Screen")})} 16 | (center 17 | (elevated-button 18 | {:onPressed (dart-cb [] 19 | (.pushNamed (-> ctx m/Navigator.of) "/second"))} 20 | (text "Launch Screen"))))) 21 | 22 | (defn second-screen [ctx] 23 | (scaffold 24 | {:appBar (app-bar 25 | {:title (m/Text "Second Screen")})} 26 | (center 27 | (elevated-button 28 | {:onPressed (dart-cb [] 29 | (-> ctx m/Navigator.of .pop))} 30 | (fx/text "Go Back!"))))) 31 | 32 | (defn make-app [] 33 | (material-app 34 | {:title "Navigation Basics" 35 | :initialRoute "/" 36 | :routes (into {} 37 | (for [[k gen] {"/" first-screen 38 | "/second" second-screen}] 39 | [k (fn ^m/Widget k [ctx] 40 | (fx/fx-render ctx 41 | (gen ctx)))]))})) -------------------------------------------------------------------------------- /examples/example/eg/x04_drawer.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x04-drawer 2 | (:require 3 | [tilton.mx.cell.core :refer [cF cF+ cF_ cI c_F]] 4 | ["package:flutter/widgets.dart" :as w] 5 | ["package:flutter/material.dart" :as m] 6 | ["package:flutter/painting.dart" :as p] 7 | [tilton.fmx.api :as fx] 8 | [tilton.mx.base :refer [dprn dp dpx]])) 9 | 10 | (defn make-app [] 11 | (fx/material-app 12 | {:title "Drawer Demo"} 13 | (fx/scaffold 14 | {:appBar (fx/app-bar 15 | {:title (m/Text "Drawer Demo")}) 16 | :drawer (cF (fx/drawer 17 | (fx/list-view 18 | {:padding m/EdgeInsets.zero} 19 | (fx/drawer-header 20 | {:decoration (m/BoxDecoration .color m/Colors.blue)} 21 | (m/Text "Drawer Header 2")) 22 | ;; below, two diff ways of getting a builder wrapper, for the right context 23 | (fx/list-tile 24 | {:title (m/Text "Item 1") 25 | :onTap (fx/within-ctx [me ctx] 26 | #(.pop (m/Navigator.of ctx)))} 27 | {:with-builder? true}) 28 | (fx/builder 29 | (fx/list-tile 30 | {:title (m/Text "Item 2") 31 | :onTap (fx/within-ctx [me ctx] 32 | #(.pop (m/Navigator.of ctx)))})))))} 33 | (fx/center 34 | (fx/text "My Ported Page!!"))))) 35 | 36 | 37 | -------------------------------------------------------------------------------- /examples/example/eg/x066_autocomplete_object.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x066-autocomplete-object 2 | "F/mx port of https://api.flutter.dev/flutter/material/Autocomplete-class.html" 3 | (:require 4 | [clojure.string :as str] 5 | [tilton.mx.api :refer [dp mget mset! mswap!] :as md] 6 | [tilton.fmx.api :as fx] 7 | [tilton.fmx.factory :as fxf] 8 | ["package:flutter/widgets.dart" :as w] 9 | ["package:flutter/material.dart" :as m] 10 | ["package:flutter/painting.dart" :as p])) 11 | 12 | ;;; --- autocomplete with object ---------------------------- 13 | 14 | (def users [{:name "Alice" :email "alice@example.com"} 15 | {:name "Bob" :email "bob@example.com"} 16 | {:name "Charlie" :email "charlie123@gmail.com"}]) 17 | 18 | (defn autocomplete-custom-type [] 19 | (#/(m/Autocomplete Map) 20 | .onSelected (fn [sel] (prn :selection!! sel)) 21 | .displayStringForOption (fn [{:keys [name email] :as opt}] 22 | (str name ": " email)) 23 | .optionsBuilder (fn [^m/TextEditingValue val] 24 | (cond 25 | (= "" (.-text val)) 26 | (.empty #/(Iterable Map)) 27 | ;-- 28 | :else 29 | (let [^#/(Iterable Map) it 30 | (.where ^List users 31 | (fn [option] 32 | (dp :jwoption option) 33 | (boolean 34 | (when (str/includes? (str option) 35 | (str/lower-case (.-text val))) 36 | option))))] 37 | it))))) 38 | 39 | (defn make-app [] 40 | (let [title "Autocomplete Basic"] 41 | (fx/material-app {:title title} 42 | (fx/scaffold 43 | {:appBar (m/AppBar .title (m/Text title))} 44 | (fx/center 45 | (fx/column {:mainAxisAlignment m/MainAxisAlignment.center} 46 | (fx/text (str "Type below one of " (str/join "," users) ".")) 47 | (autocomplete-custom-type))))))) -------------------------------------------------------------------------------- /examples/example/eg/x06_tabs.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x06-tabs 2 | (:require 3 | [tilton.fmx.api :as fx] 4 | ["package:flutter/material.dart" :as m])) 5 | 6 | ;; partial port of CLJD tabs sample, incidentally demonstrating 7 | ;; that non-MX components can be added to MX components 8 | 9 | (defn make-app 10 | [] 11 | (let [title "Tabs Demo"] 12 | (fx/material-app {:title title} 13 | (fx/default-tab-controller 14 | {:length 3} 15 | (fx/scaffold 16 | {:appBar (fx/app-bar 17 | {:bottom (m/TabBar 18 | .tabs [(m/Tab .icon (m/Icon m/Icons.directions_car)), 19 | (m/Tab .icon (m/Icon m/Icons.directions_transit)), 20 | (m/Tab .icon (m/Icon m/Icons.directions_bike))])})} 21 | (m/TabBarView 22 | .children [(m/Tab .icon (m/Icon. m/Icons.directions_car)), 23 | (m/Tab .icon (m/Icon. m/Icons.directions_transit)), 24 | (m/Tab .icon (m/Icon. m/Icons.directions_bike))])))))) -------------------------------------------------------------------------------- /examples/example/eg/x07_animated_container.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x07-animated-container 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | [tilton.mx.api :refer [dp dpx wmx-iso minfo mget mset! mupdate! mav muv fm* cF cF+ cI]] 5 | [tilton.fmx.api :as fx])) 6 | 7 | (defn random-to-double [max] 8 | (-> max rand-int .toDouble)) 9 | 10 | (defn random-color [] 11 | (m/Color.fromRGBO (rand-int 256) 12 | (rand-int 256) 13 | (rand-int 256) 14 | 1)) 15 | 16 | (defn make-app [] 17 | (fx/material-app 18 | (fx/scaffold 19 | {:appBar (fx/app-bar {:title (fx/text "Animated Container Demo")}) 20 | :floatingActionButton 21 | (cF (fx/floating-action-button 22 | {:onPressed (fx/dart-cb [] 23 | (let [anicon (fm* :anicon)] 24 | (mupdate! anicon :config assoc 25 | :width (random-to-double 300) 26 | :height (random-to-double 300) 27 | :color (random-color) 28 | :borderRadius (m/BorderRadius.circular (random-to-double 100)))))} 29 | (fx/icon m/Icons.play_arrow)))} 30 | 31 | (fx/center 32 | (fx/animated-container 33 | {:width (cF (:width (mav :config))) 34 | :height (cF (:height (mav :config))) 35 | :decoration (cF (let [config (mav :config)] 36 | (m/BoxDecoration 37 | .color (:color config) 38 | .borderRadius (:borderRadius config)))) 39 | :duration (Duration .seconds 1) 40 | :curve m/Curves.fastOutSlowIn} 41 | {:name :anicon 42 | :config (cI {:width 50.0 43 | :height 50.0 44 | :color m/Colors.green 45 | :borderRadius (m/BorderRadius.circular 8.0)})}))))) -------------------------------------------------------------------------------- /examples/example/eg/x08_navigation.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x08-navigation 2 | "Port of CLJD port of https://docs.flutter.dev/cookbook/navigation/navigation-basics" 3 | (:require 4 | ["package:flutter/material.dart" :as m] 5 | [tilton.mx.api :as mx :refer [dp]] 6 | [tilton.fmx.api :as fx 7 | :refer [within-ctx ctx-page-pop fx-render app-bar center scaffold 8 | elevated-button text builder material-app]])) 9 | 10 | (defn second-route [] 11 | (scaffold 12 | {:appBar (app-bar {:title (text "Second Route")})} 13 | (center 14 | (elevated-button 15 | {:onPressed (within-ctx [me ctx] 16 | #(ctx-page-pop ctx))} 17 | (m/Text "Go back!"))))) 18 | 19 | (defn my-ctx-page-push [ctx fx-page-def] 20 | (.push (-> ctx m/Navigator.of) 21 | (#/(m/MaterialPageRoute Object) 22 | .settings (m/RouteSettings .name "/second") 23 | .builder (fn [builder-ctx] 24 | (fx-render builder-ctx fx-page-def))))) 25 | 26 | (defn make-app [] 27 | (material-app 28 | {:title "Navigation Basics"} 29 | (scaffold 30 | {:appBar (app-bar {:title (text "First Route")})} 31 | (center 32 | (builder ;; makes Navigator visible to .of 33 | (elevated-button 34 | {:onPressed (within-ctx [me ctx] 35 | #(my-ctx-page-push ctx (second-route)))} 36 | ;;{:with-builder? true} ;; alternate way of wrapping with fresh ctx 37 | (text "Open route"))))))) -------------------------------------------------------------------------------- /examples/example/eg/x09_form_change.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x09-form-change 2 | (:require 3 | [tilton.mx.api :refer [dp dpx wmx-iso minfo mget mset! mupdate! mav muv 4 | fasc fm* cF cF+ cI cFonce ]] 5 | [tilton.fmx.api :refer [dart-cb] :as fx] 6 | ["package:flutter/widgets.dart" 7 | :refer [Text State StatefulWidget StatelessWidget] :as w] 8 | ["package:flutter/material.dart" :as m 9 | :refer [MainAxisAlignment Colors Theme Icon Icons ThemeData runApp AppBar State]] 10 | ["package:flutter/painting.dart" 11 | :refer [TextStyle]])) 12 | 13 | (defn make-app [] 14 | (let [title "Text field change detection"] 15 | (fx/material-app {:title title} 16 | (fx/scaffold 17 | {:appBar (fx/app-bar {:title (m/Text title)})} 18 | (fx/padding 19 | {:padding (m/EdgeInsets.all 16.0)} 20 | (fx/column 21 | {:mainAxisAlignment MainAxisAlignment/center} 22 | (fx/text-field 23 | {:onChanged (dart-cb [text] 24 | (mset! me :value text))} 25 | {:name :input-a 26 | :value (cI nil :watch (fn [prop me newv priorv c] 27 | (dp (str "First text field: " newv))))}) 28 | (fx/text-field 29 | {:onChanged (dart-cb [text] 30 | (mset! me :value text))} 31 | {:name :input-b 32 | :value (cI "And then...?") 33 | :controller (cFonce (let [c (m/TextEditingController .text (mget me :value))] 34 | (.addListener c 35 | (fn [] (dp (str "Second text field: " (.-text c))))) 36 | c))}) 37 | (fx/text (str "(a) " (muv :input-a) " and (b) " (muv :input-b))))))))) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/example/eg/x09_form_input.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x09-form-input 2 | "Port of CLJD faithful port of https://docs.flutter.dev/cookbook/forms/retrieve-input" 3 | (:require 4 | [tilton.mx.api :refer [dp mget mset! mswap!] :as md] 5 | [tilton.fmx.api :as fx] 6 | [tilton.fmx.factory :as fxf] 7 | ["package:flutter/widgets.dart" :as w] 8 | ["package:flutter/material.dart" :as m] 9 | ["package:flutter/painting.dart" :as p])) 10 | 11 | (defn make-app [] 12 | (let [title "Retrieve text input 2"] 13 | (fx/material-app {:title title} 14 | (fx/scaffold 15 | {:appBar (m/AppBar .title (m/Text title)) 16 | :floatingActionButton 17 | (fx/floating-action-button 18 | {:onPressed (fx/within-ctx [me ctx] 19 | #(m/showDialog 20 | .context ctx 21 | .builder (fn [ctx] 22 | (fxf/binding-ctx :show-dlg ctx 23 | (m/AlertDialog 24 | .content (m/Text (.-text ^m/TextEditingController 25 | (md/mget (md/fm* :test-input) :controller)))))))) 26 | :tooltip "Show me the value!"} 27 | {:with-builder? true} 28 | (m/Icon m/Icons.text_fields))} 29 | (fx/column {:mainAxisAlignment m/MainAxisAlignment.center} 30 | (fx/text "Enter some text, then hit the FAB!") 31 | (fx/padding 32 | {:padding (m/EdgeInsets.all 16.0)} 33 | (fx/text-field {:controller (m/TextEditingController)} 34 | {:name :test-input}))))))) 35 | 36 | -------------------------------------------------------------------------------- /examples/example/eg/x10_datatable.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x10-datatable 2 | (:require 3 | [tilton.fmx.api :as fx] 4 | ["package:flutter/material.dart" :as m])) 5 | 6 | (defn data-table [& {:keys [cols rows]}] 7 | (fx/single-child-scroll-view 8 | {:scrollDirection m/Axis.vertical} 9 | (fx/data-table 10 | {:headingTextStyle (m/TextStyle 11 | .fontWeight m/FontWeight.bold 12 | .color m/Colors.blue) 13 | :showBottomBorder true 14 | :columns (map (fn [col] 15 | (m/DataColumn .label (m/Text col))) cols) 16 | :rows (map (fn [row] 17 | (m/DataRow .cells (mapv (fn [cell] (m/DataCell (m/Text cell))) 18 | row))) rows)}))) 19 | 20 | (defn make-app [] 21 | (fx/material-app {:debugShowCheckedModeBanner false} 22 | (fx/scaffold {:appBar (fx/app-bar {:title (fx/text (str "DataTable Sample"))})} 23 | (fx/center 24 | (data-table :cols ["#" "Name" "Age" "City"] 25 | :rows [["1" "zm" "42" "guangzhou"] 26 | ["2" "zrj" "10" "guangzhou"] 27 | ["3" "wrp" "13" "hongkong"] 28 | ["4" "wrl" "11" "guangzhou"] 29 | ["1" "zm" "42" "guangzhou"] 30 | ["2" "zrj" "10" "guangzhou"] 31 | ["3" "wrp" "13" "hongkong"] 32 | ["4" "wrl" "11" "guangzhou"] 33 | ["1" "zm" "42" "guangzhou"] 34 | ["2" "zrj" "10" "guangzhou"] 35 | ["3" "wrp" "13" "hongkong"] 36 | ["4" "wrl" "11" "guangzhou"] 37 | ["1" "zm" "42" "guangzhou"] 38 | ["2" "zrj" "10" "guangzhou"] 39 | ["3" "wrp" "13" "hongkong"] 40 | ["4" "wrl" "11" "guangzhou"] 41 | ["1" "zm" "42" "guangzhou"] 42 | ["2" "zrj" "10" "guangzhou"] 43 | ["3" "wrp" "13" "hongkong"] 44 | ["4" "wrl" "11" "guangzhou"] 45 | ["1" "zm" "42" "guangzhou"] 46 | ["2" "zrj" "10" "guangzhou"] 47 | ["3" "wrp" "13" "hongkong"] 48 | ["4" "wrl" "11" "guangzhou"] 49 | ["1" "zm" "42" "guangzhou"] 50 | ["2" "zrj" "10" "guangzhou"] 51 | ["3" "wrp" "13" "hongkong"] 52 | ["4" "wrl" "11" "guangzhou"] 53 | ["5" "wrj" "10" "beijing"]]))))) -------------------------------------------------------------------------------- /examples/example/eg/x11_grid_list.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x11-grid-list 2 | "MX Port of CLJD faithful port of https://docs.flutter.dev/cookbook/lists/grid-lists" 3 | (:require 4 | [tilton.fmx.api :as fx] 5 | ["package:flutter/widgets.dart" :as w] 6 | ["package:flutter/material.dart" :as m])) 7 | 8 | (defn make-app [] 9 | (let [title "Grid List"] 10 | (fx/material-app {:title title} 11 | (fx/scaffold {:appBar (fx/app-bar {:title (m/Text "A Grid List Example")})} 12 | ; --- implicit body --- 13 | (fx/builder 14 | (fx/grid-view+count 15 | {:crossAxisCount 2} 16 | (mapv 17 | (fn [i] (fx/center 18 | (fx/text 19 | {:style (fx/within-ctx [me ctx] 20 | (-> (m/Theme.of ctx) .-textTheme .-displaySmall))} 21 | (str "Item " i)))) 22 | (range 100)))))))) -------------------------------------------------------------------------------- /examples/example/eg/x13_snackbar.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x13-snackbar 2 | "Flummox port of CLJD Faithful port of https://docs.flutter.dev/cookbook/design/snackbars" 3 | (:require 4 | ["package:flutter/material.dart" :as m] 5 | [tilton.mx.base :refer [dprn dp dpx]] 6 | [tilton.mx.api :refer [cI cF cFn cF+ minfo] :as mx] 7 | [tilton.fmx.factory :as fxf] 8 | [tilton.fmx.api :as fx 9 | :refer [snack-bar material-app scaffold center elevated-button text app-bar fx-render dart-cb]])) 10 | 11 | ;; Original: https://github.com/Tensegritics/ClojureDart/tree/main/samples/snackbar 12 | ;; ^^^ Copyright 2022 by Tensegritics, Eclipse 13 | 14 | (defn make-app [] 15 | (let [title "Snackbar Demo"] 16 | (material-app 17 | {:title title} 18 | (scaffold 19 | {:appBar (app-bar {:title (text title)})} 20 | (center 21 | (fx/builder 22 | (elevated-button 23 | {:onPressed (dart-cb [] 24 | (.showSnackBar (m/ScaffoldMessenger.of ctx) 25 | (fx-render ctx 26 | (snack-bar {:action (m/SnackBarAction 27 | .label "Undo!" 28 | .onPressed (fn [] (dart:core/print :UNDO!!!!!))) 29 | :content (text "Yay! A SnackBar!")}))))} 30 | ;; {:with-builder? true} ;; <============== option 2 31 | (text "Show text")))))))) 32 | 33 | -------------------------------------------------------------------------------- /examples/example/eg/x14_hero.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x14-hero 2 | "FlutterMX port of CLJD Faithful port of https://docs.flutter.dev/cookbook/navigation/hero-animations" 3 | (:require ["package:flutter/material.dart" :as m] 4 | [tilton.fmx.api :refer [dart-cb] :as fx])) 5 | 6 | (def detail-screen 7 | (fx/scaffold 8 | (fx/gesture-detector 9 | {:onTap (dart-cb [] 10 | (.pop (m/Navigator.of ctx)))} 11 | (fx/center 12 | (fx/hero {:tag "imageHero"} 13 | (m/Image .image (m/AssetImage "image/einstein.jpeg"))))))) 14 | 15 | (defn make-app [] 16 | (let [] 17 | (fx/material-app 18 | {:debugShowCheckedModeBanner false} 19 | (fx/scaffold 20 | {:appBar (fx/app-bar {:title (fx/text "Main Screen")})} 21 | (fx/builder 22 | (fx/gesture-detector 23 | {:onTap (dart-cb [] 24 | (.push (m/Navigator.of ctx) 25 | (#/(m/MaterialPageRoute Object) 26 | .builder (fn [ctx] 27 | (fx/fx-render ctx 28 | detail-screen)))))} 29 | (fx/hero {:tag "imageHero"} 30 | ;; required a pubspec.yaml "assets:" entry and add a path to a JPEG, 31 | (m/Image .image (m/AssetImage "image/john.jpeg"))))))))) 32 | -------------------------------------------------------------------------------- /examples/example/eg/x15_fade_widget.cljd: -------------------------------------------------------------------------------- 1 | (ns example.eg.x15-fade-widget 2 | "FlutterMX port of CLJD Faithful port of https://docs.flutter.dev/cookbook/animation/opacity-animation" 3 | (:require ["package:flutter/material.dart" :as m] 4 | [tilton.mx.api :refer [dp dpx wmx-iso minfo mget mset! mupdate! muv fm* cF cI]] 5 | [tilton.fmx.api :as fx])) 6 | 7 | (defn make-app [] 8 | (let [title "Opacity Demo"] 9 | (fx/material-app 10 | {:title title 11 | :debugShowCheckedModeBanner false} 12 | {:name :zapp} 13 | (fx/scaffold 14 | {:appBar (fx/app-bar {:title (fx/text title)}) 15 | :floatingActionButton (fx/within-ctx [me ctx] 16 | (fx/floating-action-button 17 | {:tooltip "Toggle Opacity" 18 | :onPressed #(wmx-iso (mupdate! me :visible not))} 19 | (fx/icon m/Icons.flip)))} 20 | {:visible (cI true) 21 | :name :my-home} 22 | (fx/center {} 23 | {:name :zcenter} 24 | (fx/animated-opacity 25 | {:opacity (cF (cond (true? (mget (fm* :my-home) :visible)) 1.0 26 | :else 0.0)) 27 | :duration (Duration .milliseconds 500)} 28 | {:name :ani-opa} 29 | (m/Container .width 200.0 .height 200.0 .color m/Colors.teal))))))) -------------------------------------------------------------------------------- /examples/example/non_fmx/ctx_row.cljd: -------------------------------------------------------------------------------- 1 | (ns example.non-fmx.ctx-row 2 | (:require 3 | ["package:flutter/cupertino.dart" :as cupertinoIcons] 4 | ["package:flutter/material.dart" :as m] 5 | ["package:flutter/widgets.dart" :as w] 6 | [cljd.flutter :as f] 7 | [tilton.fmx.factory :as fxf] 8 | [tilton.mx.api :as mx 9 | :refer [dp dpx cI cF cF+ cF+n cFn cFonce mget mget? mset! mswap! minfo fasc fasc-inc 10 | fmu muv fm* mav mx-bound? wmx-iso with-cc mmx-md cFkids]] 11 | [tilton.fmx.api :as fx 12 | :refer [scaffold app-bar text center column hero material-app visibility 13 | container row expanded icon padding opacity ignore-pointer 14 | checkbox-list-tile icon-button fx-render dart-cb 15 | text-field selection-area safe-area sized-box elevated-button]])) 16 | 17 | ;;; Demonstrating conditional structure decided off context 18 | 19 | (defn get-width [ctx] (.-width (.-size (m/MediaQuery.of ctx)))) 20 | 21 | (defn make-app [] 22 | (material-app 23 | {:title "F/MX Chat Arena" 24 | :theme (m/ThemeData .useMaterial3 true)} 25 | (scaffold 26 | {:appBar (app-bar {:title (text "F/MX Chat Arena")})} 27 | (center ;; {} {:dummy (cI 42)} 28 | (row {:mainAxisAlignment m/MainAxisAlignment.spaceEvenly} 29 | (when (> (get-width fxf/*ctx*) 600) 30 | (text "Hide If Not Wide")) 31 | (text "Always 1") 32 | (text "Always 2")))))) 33 | 34 | -------------------------------------------------------------------------------- /fonts/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/fonts/Inter-Regular.ttf -------------------------------------------------------------------------------- /fonts/RobotoMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/fonts/RobotoMono-Light.ttf -------------------------------------------------------------------------------- /fonts/RobotoMono-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/fonts/RobotoMono-Thin.ttf -------------------------------------------------------------------------------- /goopi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -M:cljd flutter --dart-define=GOOG_AI_API_KEY=$GOOG_AI_API_KEY 4 | -------------------------------------------------------------------------------- /image/800px-Depth-first-tree.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/800px-Depth-first-tree.svg.png -------------------------------------------------------------------------------- /image/Depth-First-Search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/Depth-First-Search.gif -------------------------------------------------------------------------------- /image/HW d Sim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/HW d Sim.png -------------------------------------------------------------------------------- /image/HW d all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/HW d all.png -------------------------------------------------------------------------------- /image/HW d chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/HW d chrome.png -------------------------------------------------------------------------------- /image/HW d macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/HW d macos.png -------------------------------------------------------------------------------- /image/cat_on_snow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/cat_on_snow.jpeg -------------------------------------------------------------------------------- /image/counter-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/counter-app.png -------------------------------------------------------------------------------- /image/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/earth.png -------------------------------------------------------------------------------- /image/einstein.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/einstein.jpeg -------------------------------------------------------------------------------- /image/game-over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/game-over.png -------------------------------------------------------------------------------- /image/hello-world-app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/hello-world-app.jpg -------------------------------------------------------------------------------- /image/jmccarthy.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/jmccarthy.jpeg -------------------------------------------------------------------------------- /image/john.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/john.jpeg -------------------------------------------------------------------------------- /image/kenny-naut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/kenny-naut.png -------------------------------------------------------------------------------- /image/kernighan.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/kernighan.jpeg -------------------------------------------------------------------------------- /image/lake-oeschinen.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/lake-oeschinen.jpeg -------------------------------------------------------------------------------- /image/scone.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/scone.jpeg -------------------------------------------------------------------------------- /image/todomvc-app.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/todomvc-app.jpeg -------------------------------------------------------------------------------- /image/trophy.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/trophy.jpeg -------------------------------------------------------------------------------- /image/under-construction.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/image/under-construction.jpeg -------------------------------------------------------------------------------- /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 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - app_links (0.0.2): 3 | - Flutter 4 | - audio_session (0.0.1): 5 | - Flutter 6 | - Flutter (1.0.0) 7 | - flutter_sound (9.19.1): 8 | - Flutter 9 | - flutter_sound_core (= 9.19.1) 10 | - flutter_sound_core (9.19.1) 11 | - flutter_tts (0.0.1): 12 | - Flutter 13 | - just_audio (0.0.1): 14 | - Flutter 15 | - path_provider_foundation (0.0.1): 16 | - Flutter 17 | - FlutterMacOS 18 | - shared_preferences_foundation (0.0.1): 19 | - Flutter 20 | - FlutterMacOS 21 | - speech_to_text (0.0.1): 22 | - Flutter 23 | - FlutterMacOS 24 | - Try 25 | - Try (2.1.1) 26 | - url_launcher_ios (0.0.1): 27 | - Flutter 28 | 29 | DEPENDENCIES: 30 | - app_links (from `.symlinks/plugins/app_links/ios`) 31 | - audio_session (from `.symlinks/plugins/audio_session/ios`) 32 | - Flutter (from `Flutter`) 33 | - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) 34 | - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) 35 | - just_audio (from `.symlinks/plugins/just_audio/ios`) 36 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 37 | - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) 38 | - speech_to_text (from `.symlinks/plugins/speech_to_text/darwin`) 39 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 40 | 41 | SPEC REPOS: 42 | trunk: 43 | - flutter_sound_core 44 | - Try 45 | 46 | EXTERNAL SOURCES: 47 | app_links: 48 | :path: ".symlinks/plugins/app_links/ios" 49 | audio_session: 50 | :path: ".symlinks/plugins/audio_session/ios" 51 | Flutter: 52 | :path: Flutter 53 | flutter_sound: 54 | :path: ".symlinks/plugins/flutter_sound/ios" 55 | flutter_tts: 56 | :path: ".symlinks/plugins/flutter_tts/ios" 57 | just_audio: 58 | :path: ".symlinks/plugins/just_audio/ios" 59 | path_provider_foundation: 60 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 61 | shared_preferences_foundation: 62 | :path: ".symlinks/plugins/shared_preferences_foundation/darwin" 63 | speech_to_text: 64 | :path: ".symlinks/plugins/speech_to_text/darwin" 65 | url_launcher_ios: 66 | :path: ".symlinks/plugins/url_launcher_ios/ios" 67 | 68 | SPEC CHECKSUMS: 69 | app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0 70 | audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207 71 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 72 | flutter_sound: 106279b6d138116ad5fe619a967a518a81bb29ee 73 | flutter_sound_core: 456fad87eeaa78cf33dca80c4a7c087487745cec 74 | flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d 75 | just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa 76 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 77 | shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 78 | speech_to_text: 627d3fd2194770b51abb324ba45c2d39398f24a8 79 | Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 80 | url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe 81 | 82 | PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef 83 | 84 | COCOAPODS: 1.16.2 85 | -------------------------------------------------------------------------------- /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.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | @main 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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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 | NSMicrophoneUsageDescription 6 | This app uses the microphone to capture and recognize voice commands. 7 | NSSpeechRecognitionUsageDescription 8 | This app uses speech recognition to get commands from user voice 9 | NSAppTransportSecurity 10 | 11 | NSAllowsArbitraryLoads 12 | 13 | 14 | io.flutter.embedded_views_preview 15 | 16 | CFBundleDevelopmentRegion 17 | $(DEVELOPMENT_LANGUAGE) 18 | CFBundleDisplayName 19 | Cljd Flutter Mx 20 | CFBundleExecutable 21 | $(EXECUTABLE_NAME) 22 | CFBundleIdentifier 23 | $(PRODUCT_BUNDLE_IDENTIFIER) 24 | CFBundleInfoDictionaryVersion 25 | 6.0 26 | CFBundleName 27 | cljd_flutter_mx 28 | CFBundlePackageType 29 | APPL 30 | CFBundleShortVersionString 31 | $(FLUTTER_BUILD_NAME) 32 | CFBundleSignature 33 | ???? 34 | CFBundleVersion 35 | $(FLUTTER_BUILD_NUMBER) 36 | LSRequiresIPhoneOS 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIMainStoryboardFile 41 | Main 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | UIViewControllerBasedStatusBarAppearance 56 | 57 | CADisableMinimumFrameDurationOnPhone 58 | 59 | UIApplicationSupportsIndirectInputEvents 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | export "cljd-out/tilton/main.dart" show main; 2 | -------------------------------------------------------------------------------- /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? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import app_links 9 | import audio_session 10 | import flutter_tts 11 | import just_audio 12 | import path_provider_foundation 13 | import shared_preferences_foundation 14 | import speech_to_text 15 | import url_launcher_macos 16 | 17 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 18 | AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) 19 | AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) 20 | FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) 21 | JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) 22 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 23 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 24 | SpeechToTextPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextPlugin")) 25 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 26 | } 27 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.15' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_macos_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - app_links (1.0.0): 3 | - FlutterMacOS 4 | - audio_session (0.0.1): 5 | - FlutterMacOS 6 | - flutter_tts (0.0.1): 7 | - FlutterMacOS 8 | - FlutterMacOS (1.0.0) 9 | - just_audio (0.0.1): 10 | - FlutterMacOS 11 | - path_provider_foundation (0.0.1): 12 | - Flutter 13 | - FlutterMacOS 14 | - shared_preferences_foundation (0.0.1): 15 | - Flutter 16 | - FlutterMacOS 17 | - speech_to_text (0.0.1): 18 | - Flutter 19 | - FlutterMacOS 20 | - Try 21 | - Try (2.1.1) 22 | - url_launcher_macos (0.0.1): 23 | - FlutterMacOS 24 | 25 | DEPENDENCIES: 26 | - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) 27 | - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) 28 | - flutter_tts (from `Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos`) 29 | - FlutterMacOS (from `Flutter/ephemeral`) 30 | - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`) 31 | - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) 32 | - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) 33 | - speech_to_text (from `Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin`) 34 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 35 | 36 | SPEC REPOS: 37 | trunk: 38 | - Try 39 | 40 | EXTERNAL SOURCES: 41 | app_links: 42 | :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos 43 | audio_session: 44 | :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos 45 | flutter_tts: 46 | :path: Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos 47 | FlutterMacOS: 48 | :path: Flutter/ephemeral 49 | just_audio: 50 | :path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos 51 | path_provider_foundation: 52 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin 53 | shared_preferences_foundation: 54 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin 55 | speech_to_text: 56 | :path: Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin 57 | url_launcher_macos: 58 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 59 | 60 | SPEC CHECKSUMS: 61 | app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a 62 | audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 63 | flutter_tts: 64651204e5d276ffea5a910f942d5e9785a96085 64 | FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 65 | just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489 66 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 67 | shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 68 | speech_to_text: 627d3fd2194770b51abb324ba45c2d39398f24a8 69 | Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 70 | url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 71 | 72 | PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 73 | 74 | COCOAPODS: 1.15.2 75 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | @main 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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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 = cljd_flutter_mx 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdFlutterMx 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.assets.pictures.read-only 8 | 9 | com.apple.security.cs.allow-jit 10 | 11 | com.apple.security.files.downloads.read-only 12 | 13 | com.apple.security.network.server 14 | 15 | com.apple.security.network.client 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /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() 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.network.client 6 | 7 | com.apple.security.app-sandbox 8 | 9 | com.apple.security.assets.pictures.read-only 10 | 11 | com.apple.security.files.downloads.read-only 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /other/physics_sim_std.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.example.physics-sim-std 2 | "Faithful port of https://docs.flutter.dev/cookbook/animation/physics-simulation#interactive-example" 3 | (:require 4 | ["package:flutter/material.dart" :as m] 5 | ["package:flutter/physics.dart" :as p] 6 | [tilton.util.base :refer [dprn]] 7 | [cljd.flutter.alpha :as f])) 8 | 9 | ;; cgrand's notes: still a relative straight port, however I chose to differ from 10 | ;; the Dart code for the handling of the _animation field. 11 | ;; Dart code uses a single listener which has a ref to a late mutable field. 12 | ;; The invariants between the value of this field, the controller and 13 | ;; the gesture detector was implicit. 14 | ;; I preferred to create a new listener at each PanEnd which closes over the animation. 15 | 16 | (defn draggable-card [& {:keys [child]}] 17 | (f/widget 18 | :inherit [m/MediaQuery] 19 | :context ctx 20 | :ticker tick 21 | :with [controller (m/AnimationController :vsync tick)] 22 | :state [drag-alignment m.Alignment/center] 23 | (let [size (.size media-query) 24 | run-animation 25 | (fn [^m/Offset px-per-s] 26 | (let [animation (.drive controller 27 | (m/AlignmentTween 28 | :begin @drag-alignment 29 | :end m.Alignment/center)) 30 | _ (dprn :boom-ani-std animation (dart/is? animation m/Animation)) 31 | _ (dprn :early-ani-val!!!!!!!! (.value animation)) 32 | units-per-s-x (/ (.dx px-per-s) (.width size)) 33 | units-per-s-y (/ (.dy px-per-s) (.height size)) 34 | units-per-s (m/Offset units-per-s-x units-per-s-y) 35 | unit-velocity (.distance units-per-s) 36 | spring ^:const (p/SpringDescription 37 | :mass 30 38 | :stiffness 1 39 | :damping 1) 40 | simulation (p/SpringSimulation spring 0 1 (- unit-velocity))] 41 | (doto controller 42 | .clearListeners 43 | (.addListener #(do 44 | ;(dprn :STD-ani animation) 45 | ;(dprn :STD-anival!!! (.value animation)) 46 | (reset! drag-alignment (.value animation)))) 47 | (.animateWith simulation))))] 48 | (f/nest 49 | (m/GestureDetector 50 | :onPanDown (fn [details] (.stop controller) 51 | nil) 52 | :onPanUpdate (fn [^m/DragUpdateDetails details] 53 | (dprn :updetails (/ (-> details .delta .dx) (/ (.width size) 2)) 54 | (/ (-> details .delta .dy) (/ (.height size) 2))) 55 | (swap! drag-alignment 56 | #(.+ (m/Alignment 57 | (/ (-> details .delta .dx) (/ (.width size) 2)) 58 | (/ (-> details .delta .dy) (/ (.height size) 2))) 59 | %)) 60 | nil) 61 | :onPanEnd (fn [^m/DragEndDetails details] 62 | (run-animation (-> details .velocity .pixelsPerSecond)) 63 | nil)) 64 | (m/Align :alignment @drag-alignment) 65 | m/Card 66 | child)))) 67 | 68 | (def physics-card-demo 69 | (f/widget 70 | (m/Scaffold 71 | :appBar (m/AppBar) 72 | :body (draggable-card :child (m/FlutterLogo :size 128))))) 73 | 74 | ;(defn main [] 75 | ; (m/runApp (m/MaterialApp :home physics-card-demo))) 76 | 77 | (defn make-app [] 78 | (m/MaterialApp :home physics-card-demo)) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | jar 5 | flutter-mx 6 | flutter-mx 7 | 0.1.0 8 | flutter-mx 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/tilton/fmx/material.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.fmx.material 2 | (:require 3 | ["dart:io" :as io] 4 | ["package:flutter/foundation.dart" :as foundation] 5 | ["package:flutter/material.dart" :as m] 6 | ["package:flutter/widgets.dart" :as w] 7 | ["package:flutter/painting.dart" :as p] 8 | [tilton.fmx.factory :refer [deftag] :as fxf])) 9 | -------------------------------------------------------------------------------- /src/tilton/fmx/widgets.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.fmx.widgets 2 | (:require 3 | ["dart:io" :as io] 4 | ["package:flutter/foundation.dart" :as foundation] 5 | ["package:flutter/material.dart" :as m] 6 | ["package:flutter/widgets.dart" :as w] 7 | ["package:flutter/painting.dart" :as p] 8 | [tilton.fmx.factory :refer [deftag] :as fxf])) 9 | -------------------------------------------------------------------------------- /src/tilton/main.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.main 2 | (:require 3 | ["package:flutter/material.dart" :as m] 4 | ["package:flutter/widgets.dart" :as w] 5 | ["package:flutter/foundation.dart" :as f] 6 | ["package:supabase_flutter/supabase_flutter.dart" :as supa] 7 | ["dart:io" :as io] 8 | ;[cljd.flutter :as f] 9 | [tilton.mx.cell.base :as cty] 10 | [tilton.mx.model.core :as md] 11 | [tilton.mx.util :as mxu] 12 | [tilton.mx.base 13 | :refer [wtrx dp dpx trx *fx$dpk*]] 14 | [tilton.mx.api :refer [navdbg minfo cinfo] :as mx] 15 | [tilton.fmx.factory :refer [fx$sst-registry-clear]] 16 | [tilton.fmx.api :as fx] 17 | [tilton.testing :as testing] 18 | [example.driver :as eg] ;; <--- comment out when excluding examples dir in deps.edn 19 | [example.eg.x01-counter :as excounter] 20 | [tilton.counter-app :as counter] ;; BROKEN. this one uses sugary defs for scaffold and material-app 21 | #_[learn.counter.counter-fmx :as l-ctr])) 22 | 23 | ;;; The main branch as-is excludes all but one example. To pull those in: 24 | ;;; * modify deps.edn to include "examples" in :paths; 25 | ;;; * uncomment [example.driver..] above; 26 | ;;; * uncomment (eg/select) below; and 27 | ;;; * restart the app to pick up the deps.edn. 28 | 29 | (defn main [] 30 | (binding [#_#_ *async-error-handler* (fn [exc stack-trace] 31 | (dp :ASYNC-ERROR-TRAPS exc) 32 | (dp :ASYNC-ERROR-stack-trace stack-trace)) 33 | *print-level* 5 34 | *print-length* 10 35 | *print-readably* true] 36 | (dp :main-entry--------------------------------------------) 37 | 38 | 39 | (fx/initialize) 40 | 41 | (binding [cty/*dpc-enabled* true] 42 | ; *fx$dpk* [:propagate :pulse :cset :cnset bbuild :bbuild+ :gg :sstate :sstate+] 43 | (.ensureInitialized w/WidgetsFlutterBinding) 44 | 45 | ; if using Supabase, activate this: 46 | #_ (do (dp :supa-URL (String/fromEnvironment "SUPA_MVX_URL")) 47 | (dp :supa-KEY (String/fromEnvironment "SUPA_MVX_KEY")) 48 | (dp :Supa-init 49 | (await (.initialize supa/Supabase 50 | .url (String/fromEnvironment "SUPA_MVX_URL") 51 | .anonKey (String/fromEnvironment "SUPA_MVX_KEY"))))) 52 | 53 | (if false ;; as of 11/2024 we seem not to be able to run outside run-fx-app-hot 54 | (excounter/make-app) 55 | (fx/run-fx-app-hot 56 | (if false 57 | (excounter/make-app) 58 | (eg/select))))) 59 | 60 | #_(testing/run-tests))) 61 | 62 | #_(when (not (fx/is-web?)) 63 | (dp :platform-processors io/Platform.numberOfProcessors)) 64 | 65 | ;; (set! r/debugPaintSizeEnabled true) 66 | ;; (w/debugDumpApp) 67 | 68 | (defn sample-debugger [opcode data] 69 | (case opcode 70 | :mark-rebuild-unless-defunct 71 | (do) #_(let [{:keys [cell element]} data] 72 | (dp :adtata data) 73 | (dp :cell (cinfo cell)) 74 | (dp :cellkeys (keys @cell)) 75 | (let [elt ^w/Element element] 76 | (when (not (and (.-mounted elt) 77 | (.-debugIsActive elt) 78 | (not (.-debugIsDefunct elt)))) 79 | (dp :rebld-DEAD-ELT-me!!! (minfo (:me @cell))) 80 | (dp :rebld-mounted (.-mounted elt)) 81 | (dp :rebld-active (.-debugIsActive elt)) 82 | (dp :rebld-sees-defunct (.-debugIsDefunct elt)) 83 | (dp :rebld-elt-str (.toString elt))))) 84 | (dp :unrecognized-debug-opcode opcode data))) -------------------------------------------------------------------------------- /src/tilton/mx/cell/observer.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.mx.cell.observer 2 | (:require 3 | [tilton.mx.foundation :refer [observe mx-type] :as mx] 4 | [tilton.mx.base 5 | :refer [trx dpx dp mx-throw]] 6 | 7 | [tilton.mx.util 8 | :refer [cl-find set-ify atom? 9 | make-fifo-queue fifo-empty? fifo-peek fifo-pop 10 | fifo-data fifo-add rmap-set!] 11 | :as ut] 12 | 13 | [tilton.mx.cell.base 14 | :refer [ unbound 15 | +pulse+ c-prop c-value c-mname 16 | c-model] :as cty] 17 | 18 | [tilton.mx.model.peek :refer [chk md-type mref? minfo cinfo cref?]] 19 | 20 | ["package:flutter/widgets.dart" :as w 21 | :refer [Text Center Expanded Column State StatefulWidget StatelessWidget]])) 22 | 23 | (def +observe-method+ (atom {})) 24 | 25 | (defn observer-register [key observer] 26 | (prn :watch-reg key) 27 | (swap! +observe-method+ assoc key observer)) 28 | 29 | (def +observe-default-handler+ (atom nil)) 30 | 31 | (defn observer-get [key] 32 | (get @+observe-method+ key)) 33 | 34 | (defn fx-observe [prop-name me new-val old-val c] 35 | (chk me (str "model observe invoked for standalone cell? " (cinfo c))) 36 | (dpx :watch-oskool prop-name (minfo me) ) 37 | 38 | (when-let [obs (:fx$observer @me)] 39 | ;; note that we carry on with generic observe after specific observe 40 | (do (dpx :oskool-using-obj-observer (minfo me)) 41 | (obs prop-name me new-val old-val c))) 42 | 43 | (when-let [obs (observer-get (mx-type me))] 44 | (do (dpx :oskool-using-type-obs prop-name (mx-type me)) 45 | (obs prop-name me new-val old-val c)))) 46 | 47 | (defmacro fn-obs 48 | "Shortcut definer for cell-specific observers. 49 | body can be multiple sexprs with access to 50 | call parameters: prop, me, new, old, and c." 51 | [& body] 52 | `(fn [~'prop ~'me ~'new ~'old ~'c] 53 | ~@body)) 54 | 55 | (defn c-observe 56 | ([c why] 57 | (c-observe c unbound why)) 58 | 59 | ([c prior-value why] 60 | (chk (cref? c) (str "cref? fail on c-observe" (cinfo c))) 61 | (chk (dart/is? @+pulse+ int)) 62 | (dpx :c-observe> why (cinfo c)) 63 | 64 | (rmap-set! [:pulse-observed c] @+pulse+) 65 | (when-let [me (c-model c)] ;; not in standalone cells, mostly in test suite 66 | ;; we do observes specified for types or slots... 67 | (fx-observe (c-prop c) me (c-value c) prior-value c) 68 | 69 | (when-let [md-type (md-type (c-model c))] 70 | (mx/observe md-type (c-prop c) me (c-value c) prior-value c))) 71 | 72 | ;; ...and also do observes specified ad hoc on the cI/cF call. 73 | ;; nb that we do not want ad hoc observers to shadow those specified generically 74 | ;; indeed, in Lisp observers are progn methods -- they all run. 75 | (when-let [cell-observer (:obs @c)] 76 | (cell-observer (c-prop c) (c-model c) (c-value c) prior-value c)))) 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/tilton/mx/cell/synapse.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.mx.cell.synapse 2 | (:require 3 | [tilton.mx.model.peek :refer [chk mref? minfo]] 4 | [tilton.mx.base :refer [dp]] 5 | [tilton.mx.util :refer [ pln rmap-set!]] 6 | 7 | [tilton.mx.cell.base 8 | :refer [*depender* c-synapses c-prop c-useds]] 9 | 10 | [tilton.mx.cell.integrity 11 | :refer [with-integrity]] 12 | 13 | [tilton.mx.cell.evaluate :refer [ cget c-value-assume 14 | record-dependency ensure-value-is-current]] 15 | 16 | [tilton.mx.cell.observer :refer [fn-obs]] 17 | 18 | [tilton.mx.cell.core 19 | :refer [cI make-c-formula c-fn]])) 20 | 21 | (defn existing-syn [synapse-id] 22 | (chk (keyword? synapse-id) "Synapse ID must be a keyword") 23 | (chk *depender* (str "You attempted to create synapse " synapse-id " outside a Cell formula. Synapses serve containing Cells.")) 24 | (some #(when (= synapse-id (:synapse-id (deref %))) %) 25 | (c-synapses *depender*))) 26 | 27 | (defmacro with-synapse [[synapse-id [& closure-bindings]] & body] 28 | `(let [existing-syn# (existing-syn ~synapse-id) 29 | synapse# (or existing-syn# 30 | 31 | (let [new-syn# 32 | (let [~@closure-bindings] 33 | ;; (dp :making-syn!? (:prop @*depender*)) 34 | (make-c-formula 35 | :model (:model @*depender*) 36 | :prop ~synapse-id 37 | :synapse-id ~synapse-id 38 | :code '~body 39 | :synaptic? true 40 | :rule (c-fn ~@body)))] 41 | ;;(dp :built-synapse!!!!!!!!!!!!!!!! ~synapse-id @new-syn#) 42 | (rmap-set! [:synapses *depender*] 43 | (conj (c-synapses *depender*) new-syn#)) 44 | (record-dependency new-syn#) ;; needed?!!!! 45 | ;; (dp :made-syn!!!!!!!!!!!! @new-syn#) 46 | new-syn#)) 47 | 48 | value# (tilton.mx.cell.integrity/with-integrity () 49 | ;; (dp :with-syn-ensure-syn-value (nil? existing-syn#)) 50 | (ensure-value-is-current synapse# :synapse *depender*))] 51 | ;;(dp :synapse-returns ~synapse-id :useds (doall (map c-prop (c-useds synapse#)))) 52 | (record-dependency synapse#) 53 | value#)) 54 | 55 | (defn call-with-synapse [synapse-id cell-factory] 56 | (let [existing-syn (existing-syn synapse-id) 57 | synapse (or existing-syn 58 | (let [new-syn (cell-factory)] 59 | (dp :building-synapse ~synapse-id) 60 | (rmap-set! [:synapses *depender*] 61 | (conj (c-synapses *depender*) new-syn)) 62 | (record-dependency new-syn) ;; needed?!!!! 63 | new-syn)) 64 | 65 | value (tilton.mx.cell.integrity/with-integrity () 66 | (ensure-value-is-current synapse :synapse *depender*))] 67 | (record-dependency synapse) 68 | 69 | value)) 70 | 71 | (defmacro cSyn [[synapse-id [& closure-bindings]] & body] 72 | `(call-with-synapse ~synapse-id #(let [~@closure-bindings] 73 | (make-c-formula 74 | :model (c-model *depender*) 75 | :prop ~synapse-id 76 | :synapse-id ~synapse-id 77 | :code '~body 78 | :synaptic? true 79 | :rule (c-fn ~@body))))) -------------------------------------------------------------------------------- /src/tilton/mx/foundation.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.mx.foundation 2 | (:require [clojure.string :as str])) 3 | 4 | (defprotocol PObserver 5 | (observe [this prop me new-value prior-value cell])) 6 | 7 | (deftype MXImplementer []) 8 | 9 | ;; --- mx-common ---------------------- 10 | 11 | (defn mx-type [it] 12 | (when-let [m (meta it)] 13 | (:mx-type m))) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/tilton/test/family_kids.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.test.family-kids 2 | (:require 3 | [tilton.mx.foundation :refer [mx-type]] 4 | [tilton.mx.base 5 | :refer [trx dp dpx prog1 *trx?*]] 6 | 7 | [tilton.mx.cell.base 8 | :refer [without-c-dependency cells-init c-optimized-away? c-formula? c-value c-optimize 9 | c-unbound? c-input? 10 | c-model c-valid? c-useds 11 | c-state +pulse+ c-pulse-observed 12 | *call-stack* *defer-changes* unbound 13 | c-rule c-me c-value-state c-callers 14 | unlink-from-callers *causation* 15 | c-prop-name c-synaptic? 16 | c-pulse c-pulse-last-changed c-ephemeral? c-prop c-props 17 | c-lazy] :as cty] 18 | [tilton.mx.cell.integrity :refer [with-integrity]] 19 | [tilton.mx.cell.observer 20 | :refer [fn-obs]] 21 | [tilton.mx.cell.core 22 | :refer [cF cF+ c-reset-next! cFonce cFn 23 | cI cset! make-cell make-c-formula]] 24 | [tilton.mx.cell.evaluate :refer [cget]] 25 | [tilton.mx.model.peek :refer [mref? cref?]] 26 | [tilton.mx.model.base :refer [md-cz md-cell]] 27 | [tilton.mx.model.core 28 | :refer [the-kids mdv! fm! make mset! *md-quiesce-log?*] 29 | :as md] 30 | [tilton.mx.api :refer [dp dpx wmx-iso minfo mget mset! mupdate! mav muv 31 | navig fasc fm* cF cF+ cI cFonce ]])) 32 | 33 | (defn k-notq2be [] 34 | (binding [*md-quiesce-log?* true] 35 | (let [f (md/make-family 36 | :ee (cI 2) 37 | :kids (cF (the-kids 38 | (when (odd? (mget me :ee)) 39 | (md/make 40 | :name :yep 41 | :value (cF+ [:dbg :quiesce] 42 | (do 43 | (let [par (:parent @me)] 44 | (let [ee (mget par :ee)] 45 | (* 14 ee))))))))))] 46 | (assert (dart/is? (mx-type f) md/Family) 47 | (str "k-notq2be bad family")) 48 | (assert (empty? (mget f :kids))) 49 | 50 | (do 51 | (mset! f :ee 3) 52 | (assert (not (empty? (mget f :kids)))) 53 | (assert (= 42 (mdv! :yep :value f))) 54 | 55 | (dp :ok-42!!) 56 | (let [dmw (first (mget f :kids))] 57 | (assert (mref? dmw)) 58 | (dp :ok-42-2!!) 59 | (mset! f :ee 0) 60 | (dp :ok-42-3!!) 61 | (assert (empty? (mget f :kids))) 62 | 63 | ;; (dp :dmw @dmw :meta (meta dmw)) 64 | ;; todo get kids observe to quiesce kids 65 | 66 | (assert (= :md-quiesced (:state (meta dmw))))) 67 | (dp :k-notq2be-exit))))) 68 | 69 | (defn run-tests [] 70 | (k-notq2be) 71 | (dp :family-kids-OK)) 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/tilton/test/observer.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.test.observer 2 | (:require 3 | [tilton.mx.base 4 | :refer [trx dp dpx prog1]] 5 | 6 | [tilton.mx.foundation :refer [mx-type]] 7 | [tilton.mx.model.peek :refer [minfo mref? minfo c-type cref? cinfo Cell CellFormula]] 8 | [tilton.mx.cell.base 9 | :refer [without-c-dependency c-optimized-away? c-formula? c-value c-optimize 10 | c-unbound? c-input? 11 | cells-init c-callers c-useds 12 | c-model c-valid? c-useds 13 | c-state +pulse+ c-pulse-observed 14 | *call-stack* *defer-changes* 15 | c-rule c-me c-value-state c-callers 16 | unlink-from-callers *causation* 17 | c-prop-name c-synaptic? 18 | c-pulse c-pulse-last-changed c-ephemeral? c-prop 19 | c-lazy] :as cty] 20 | [tilton.mx.cell.evaluate :refer [cget]] 21 | [tilton.mx.cell.observer :refer [fn-obs]] 22 | 23 | [tilton.mx.cell.core 24 | :refer [cF cF+ cI cset!]] 25 | [tilton.mx.model.peek :refer [mref?]] 26 | )) 27 | 28 | (defn t-formula [] 29 | (cells-init) 30 | (let [bingo (atom false) 31 | c (cF+ [:prop :bingo 32 | :watch (fn-obs 33 | (reset! bingo true))] 34 | (+ 40 2))] 35 | (assert (dart/is? (c-type c) CellFormula)) 36 | (assert (= (c-value-state c) :unbound)) 37 | (assert (= #{} (c-callers c))) 38 | (assert (= #{} (c-useds c))) 39 | (assert (not (c-input? c))) 40 | (assert (not (c-valid? c))) 41 | (assert (nil? (c-model c))) 42 | (dp :cget-before (cget c) :deref (cinfo c)) 43 | (assert (= (cget c) 42)) 44 | (assert @bingo) 45 | )) 46 | 47 | (defn test-input [] 48 | (let [bingo2 (atom 0) 49 | c (cI 42 :prop :bingo2 50 | :watch (fn-obs 51 | (dp :test-input-obs-runs!!!) 52 | (swap! bingo2 inc)))] 53 | (assert (dart/is? (c-type c) Cell)) 54 | (assert (= (c-value-state c) :valid)) 55 | (assert (= #{} (c-callers c))) 56 | (assert (c-input? c)) 57 | (assert (c-valid? c)) 58 | (assert (nil? (c-model c))) 59 | (assert (= :bingo2 (c-prop c) (c-prop-name c))) 60 | (assert (= (cget c) 42)) 61 | (assert (= 1 @bingo2)) 62 | 63 | (cset! c 54) 64 | (assert (= (cget c) 54)) 65 | (assert (= 2 @bingo2)))) 66 | 67 | (defn t-custom-obs [] 68 | (let [bobs (atom nil) 69 | b (cI 2 :prop :bb 70 | :watch (fn-obs 71 | (dp :watch-b prop me new old) 72 | (reset! bobs new))) 73 | cobs (atom nil) 74 | c (cF+ [:watch (fn-obs [prop me new old c] 75 | (trx prop me new old) 76 | (reset! cobs new))] 77 | (* 10 (cget b)))] 78 | (do 79 | (dp :MX-built!------------------) 80 | (assert (= @bobs nil) (str "@bobs not nil: " @bobs)) 81 | (assert (= (cget b) 2)) 82 | (assert (= @bobs 2) (str "@bobs not nil: " @bobs)) 83 | (assert (= (cget c) 20)) 84 | (assert (= @cobs 20)) 85 | (cset! b 3) 86 | (assert (= 3 @bobs)) 87 | (assert (= 30 (cget c))) 88 | (assert (= 30 @cobs))))) 89 | 90 | (defn run-tests [] 91 | (t-formula) 92 | (test-input) 93 | (t-custom-obs) 94 | (dp :observer-tests-OK)) 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/tilton/testing.cljd: -------------------------------------------------------------------------------- 1 | (ns tilton.testing 2 | (:require 3 | [tilton.mx.base :refer [dp]] 4 | [tilton.test.cell-core :refer [run-tests] :as test-cell-core] 5 | [tilton.test.hello-cells :refer [run-tests] :as hello-cells] 6 | [tilton.test.evaluate :refer [run-tests] :as test-eval] 7 | [tilton.test.observer :refer [run-tests] :as test-obs] 8 | [tilton.test.integrity :refer [run-tests] :as test-integ] 9 | [tilton.test.lazy-cells :refer [run-tests] :as test-lazy] 10 | ;[tilton.test.synapse :refer [run-tests] :as test-syn] 11 | [tilton.test.model-core :refer [run-tests] :as md] 12 | [tilton.test.family-kids :refer [run-tests] :as fm-kids])) 13 | 14 | (defn run-test-lazy [] 15 | (test-lazy/run-tests) 16 | (dp :test-lzy-ok)) 17 | 18 | (defn run-tests [] 19 | (dp :----------------------start-tests) 20 | (do (test-cell-core/run-tests) 21 | (dp :------------------cell-core-ok)) 22 | (hello-cells/run-tests) 23 | (dp :----------------------hello-cells-ok) 24 | (test-eval/run-tests) 25 | (dp :--------------------eval-ok) 26 | (test-obs/run-tests) 27 | (dp :----------------obs-watch-ok) 28 | (test-integ/run-tests) 29 | (dp :----------------------integ-ok) 30 | (test-lazy/run-tests) 31 | (dp :---------------------------lazy-ok) 32 | (md/run-tests) 33 | (dp :--------------------------md-ok) 34 | (fm-kids/run-tests) 35 | (dp :----------------------------------fm-kids-ok) 36 | ; TODO synapses (test-syn/run-tests) 37 | (hello-cells/run-tests) 38 | (dp "-------------------------testing-OK")) 39 | 40 | -------------------------------------------------------------------------------- /sup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -M:cljd flutter --dart-define=SUPA_MVX_URL=$SUPA_MVX_URL \ 4 | --dart-define=SUPA_MVX_KEY=$SUPA_MVX_KEY 5 | -------------------------------------------------------------------------------- /sup_macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -M:cljd flutter -d macos \ 4 | --dart-define=SUPA_MVX_URL=$SUPA_MVX_URL \ 5 | --dart-define=SUPA_MVX_KEY=$SUPA_MVX_KEY 6 | -------------------------------------------------------------------------------- /supmvx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -M:cljd flutter --dart-define=SUPA_MVX_URL=$SUPA_MVX_URL \ 4 | --dart-define=SUPA_MVX_KEY=$SUPA_MVX_KEY 5 | -------------------------------------------------------------------------------- /supweb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -M:cljd flutter -d chrome \ 4 | --dart-define=SUPA_MVX_URL=$SUPA_MVX_URL \ 5 | --dart-define=SUPA_MVX_KEY=$SUPA_MVX_KEY 6 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matrix", 3 | "short_name": "matrix", 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/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 | 13 | void RegisterPlugins(flutter::PluginRegistry* registry) { 14 | AppLinksPluginCApiRegisterWithRegistrar( 15 | registry->GetRegistrarForPlugin("AppLinksPluginCApi")); 16 | FlutterTtsPluginRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("FlutterTtsPlugin")); 18 | UrlLauncherWindowsRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 20 | } 21 | -------------------------------------------------------------------------------- /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 | app_links 7 | flutter_tts 8 | url_launcher_windows 9 | ) 10 | 11 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 21 | endforeach(plugin) 22 | 23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "utils.cpp" 8 | "win32_window.cpp" 9 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 10 | "Runner.rc" 11 | "runner.exe.manifest" 12 | ) 13 | apply_standard_settings(${BINARY_NAME}) 14 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 15 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 16 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 17 | add_dependencies(${BINARY_NAME} flutter_assemble) 18 | -------------------------------------------------------------------------------- /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 | #ifdef FLUTTER_BUILD_NUMBER 64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0 67 | #endif 68 | 69 | #ifdef FLUTTER_BUILD_NAME 70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME 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", "com.example" "\0" 93 | VALUE "FileDescription", "matrix" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "matrix" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "matrix.exe" "\0" 98 | VALUE "ProductName", "matrix" "\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 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /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"matrix", 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/kennytilton/flutter-mx/c177b2eec9af462cb8fea3f8ae0b1f255e267105/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 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 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.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 | --------------------------------------------------------------------------------