Initial commit: two Clojure Android todo apps

Side-by-side comparison of viable Clojure-on-Android approaches:
- todo-expo/: ClojureScript + shadow-cljs + Expo + Reagent + re-frame
- todo-flutter/: ClojureDart + Flutter

Both apps feature: add/remove/check-off todos, SQLite persistence,
categories, priorities, edit support, swipe-to-delete, filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 23:41:45 -05:00
commit 453d017558
174 changed files with 27073 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
# Node
node_modules/
# Shadow-cljs
.shadow-cljs/
.nrepl-port
# Expo / React Native
todo-expo/app/
todo-expo/.expo/
todo-expo/android/
todo-expo/ios/
# Flutter / ClojureDart
todo-flutter/build/
todo-flutter/.clojuredart/
todo-flutter/.dart_tool/
todo-flutter/.cpcache/
todo-flutter/.packages
# Clojure
.cpcache/
# IDE
.idea/
*.iml
.vscode/
# OS
.DS_Store
Thumbs.db
+1
View File
@@ -0,0 +1 @@
{:lint-as {reagent.core/with-let clojure.core/let}}
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [PEZ, bpringe]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+22
View File
@@ -0,0 +1,22 @@
node_modules/**/*
.expo/*
npm-debug.*
*.jks
*.p12
*.key
*.mobileprovision
out/
.shadow-cljs/
.nrepl-port
pom.xml
.idea/
*.iml
app
.cpcache
/web-build
.calva/output-window/
.DS_Store
.lsp/.cache
.clj-kondo/.cache
.lsp/sqlite.db
+13
View File
@@ -0,0 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="REPL" type="ClojureREPL" factoryName="Remote" activateToolWindowBeforeRun="false">
<module name="rn-rf-shadow" />
<setting name="host" value="" />
<setting name="port" value="0" />
<setting name="replType" value="NREPL" />
<setting name="configType" value="PORT_FILE" />
<setting name="replPortFileType" value="STANDARD" />
<setting name="customPortFile" value="" />
<setting name="fixLineNumbers" value="false" />
<method v="2" />
</configuration>
</component>
+1
View File
@@ -0,0 +1 @@
{}
+209
View File
@@ -0,0 +1,209 @@
# React Native using shadow-cljs in 3 minutes
The fastest way a [ClojureScript](https://clojurescript.org/) coder can get started with React Native development. *Prove me wrong.*
This is an example project, only slightly beyond *Hello World*, using: [shadow-cljs](https://github.com/thheller/shadow-cljs), [React Native](https://facebook.github.io/react-native/), [Expo](https://expo.io/), [Reagent](https://reagent-project.github.io/), and [re-frame](https://github.com/Day8/re-frame).
<div style="display: flex; justify-content: space-around;">
<div style="flex: 1"><img src="./rn-rf-shadow.png" width="240" /></div>
<div style="flex: 1">Check this video out for a demo of this project.<br>
<a href="https://www.youtube.com/watch?v=QsUj7HO5xDg"><img src="https://img.youtube.com/vi/QsUj7HO5xDg/maxresdefault.jpg" width="320px"><br>
ClojureScript ❤️ React Native</a>
</div>
</div>
Follow along to get started. There are instructions for [Calva](http://calva.io), [Emacs/CIDER](https://cider.mx), [Cursive](https://cursive-ide.com), and the command line. It is assumed you have Java and Node installad as well as dev tool chains for the platforms you are targeting. (If you are targeting the Web, then Chrome is enough.)
## Installing
To facilitate that you can easily try this out without installing anything globally on your machine, this project installs everything it needs locally in `node_modules`. Then `npx` is used to execute tools like `expo-cli`.
To install dependencies, and setup the project, run:
1. `npm i`
From there use your favorite editor and/or the prompt.
## Using VS Code + Calva
Assuming you have installed the [Calva](https://calva.io) extension in VS Code:
### Build and start the app, and connect Calva
1. Open the project in VS Code. Then:
1. Run the Calva command **Start a Project REPL and Connect (aka Jack-in)**
1. Wait for shadow to build the project.
### Start Expo
1. Then **Run Build Task**. This will start Expo and the Metro
bundler. Wait for expo to show its menu options in the terminal pane.
1. In the expo menu press w for **open web**.
The app now should be running in your web browser and Calva automatically connects to it. Confirm this by evaluating something like this in Calva (from a cljs file or in the REPL window):
``` clojure
(js/alert "Hello world!")
```
You should see the alert pop up where the app is running.
Of course you should try to fire up the app on all simulators, emulators and phones you have as well. Please note that Calva will only be connected to one of your apps at a time, and it is a bit arbitrary which one. Use `(js/alert)` to check this.
## Using Emacs with CIDER
Open Emacs and a bash shell:
1. Run `npx shadow-cljs compile :app` to perform an initial build of the app.
1. In Emacs open one of the files in the project (`deps.edn` is fine)
1. From that buffer, do `cider-jack-in-clojurescript` [C-c M-J] to
launch a REPL. Follow the series of interactive prompts in the
minibuffer:
1. select `shadow-cljs` as the command to launch
1. select `shadow` as the repl type
1. select `:app` as the build to connect
1. and optionally answer `y` or `n` to the final question about
opening the `shadow-cljs` UI in a browser.
At this point `shadow-cljs` will be watching the project folder and
running new builds of the app if any files are changed. You'll also
have a REPL prompt, *however the REPL doesn't work because it isn't
connected to anything. The app isn't running yet.*
1. In a shell run `npm run ios` (same as `npx expo start -i`). This starts
the Metro bundler, perform the bundling, launch the iPhone
simulator, and transmit the bundled app. Be patient at this step as
it can take many seconds to complete. When the app is finally
running expo will display the message:
WebSocket connected!
REPL init successful
1. Once you see that the REPL is initalized, you can return to Emacs
and confirm the REPL is connected and functional:
``` clojure
cljs.user> (js/alert "hello world!")
```
Which should pop-up a modal alert in the simulator, confirming the
app is running and the REPL is connected end to end.
## Using IntelliJ + Cursive REPL
1. Follow the instructions specified in [Or the Command line](#or-the-command-line).
2. Create a Maven POM using `shadow-cljs pom`, as described in the [Shadow doc](https://shadow-cljs.github.io/docs/UsersGuide.html#_cursive).
3. There are now two options
1. If you already have a project open, open the project in IntelliJ using _File | New | Project from existing sources..._ and indicating the `pom.xml` file.
2. If you're at the welcome screen, press the "Open" button and navigate to the `pom.xml`.
5. Ensure the project has an SDK configured using _File | Project Structure_, and checking under `Project`.
7. The project comes with a REPL run configuration called "REPL". Run the REPL using the _Run | Run 'REPL'_ menu item, or the toolbar button.
8. Run the commands in [Using ClojureScript REPL](#using-clojurescript-repl)
## Or the Command line
```sh
$ npm i
$ npx shadow-cljs watch app
# wait for first compile to finish or expo gets confused
# on another terminal tab/window:
$ npm start
```
This will run Expo DevTools at http://localhost:19002/
To run the app in browser using expo-web (react-native-web), press `w` in the same terminal after expo devtools is started.
This should open the app automatically on your browser after the web version is built. If it does not open automatically, open http://localhost:19006/ manually on your browser.
Note that you can also run the following instead of `npm start` to run the app in browser:
```
# same as npx expo start --web
$ npm run web
# or
# same as npx expo start --web-only
$ npm run web-only
```
### Using ClojureScript REPL
Once the app is deployed and opened in phone/simulator/emulator/browser, connect to nrepl and run the following:
```clojure
(shadow/nrepl-select :app)
```
NB: _Calva users don't need to do ^ this ^._
To test the REPL connection:
```clojure
(js/alert "Hello from Repl")
```
### Command line CLJS REPL
Shadow can start a CLJS repl for you, if you prefer to stay at the terminal prompt:
```bash
$ npx shadow-cljs cljs-repl :app
```
## Disabling Expo Fast Refresh
You will need to disable **Fast Refresh** provided by the Expo client, which conflicts with shadow-cljs hot reloading. You really want to use Shadow's, because it is way better and way faster than the Expo stuff is.
For the iOS and Android there is a **Disable Fast Refresh** option in the [development menu](https://docs.expo.io/workflow/debugging/#developer-menu). NB: _Often you need to first enable it and then disable it._
For web there may be some way to disable it via a `webpack.config` file as per [this example](https://docs.expo.dev/guides/customizing-webpack/#example). But failing that, once the app has loaded you can block requests to/from `localhost:19006/*` (the Webpack dev server) in devtools [like so](https://github.com/facebook/create-react-app/issues/2519#issuecomment-318867289), for instance by right-clicking on a request in the Network tab, selecting `Block request URL`, then editing the pattern. In Chrome this looks something like:
![image](https://github.com/CarnunMP/rn-rf-shadow/assets/8897392/4d5d9541-f5e4-4108-a38e-65b3c2da4939)
![image](https://github.com/CarnunMP/rn-rf-shadow/assets/8897392/27c94aa8-3337-4fde-b7f6-7ce87197a89d)
This workaround is far from ideal, because the block needs to be manually toggled *off* whenever a full refresh is required (e.g. to load a new file), then back on again. But it seems to do the job.
## Production builds
A production build involves first asking shadow-cljs to build a release, then to ask Expo to work in Production Mode.
1. Kill the watch and expo tasks.
1. Execute `shadow-cljs release app`
1. Start the expo task (as per above)
1. Enable Production mode.
1. Start the app.
### Using EAS Build
`expo build` is the classic way of building an Expo app, and `eas build` is the new version of `expo build`. Using EAS Build currently requires an Expo account with a paid plan subscription.
The steps below provide an example of using EAS Build to build an apk file to run on an Android emulator or device.
0. Install the latest EAS CLI by running `npm install -g eas-cli`
0. Log into your Expo account
0. Configure EAS Build in your project with `eas build:configure`.
0. Make your eas.json file contents look like this:
```json
{
"build": {
"production": {},
"development": {
"distribution": "internal",
"android": {
"buildType": "apk"
},
"ios": {
"simulator": true
}
}
}
}
```
0. Commit your changes, run `eas build --profile development`, and follow the prompts.
0. Navigate to the URL given by the command to monitor the build. When it completes, download the apk and install it on your device or emulator.
See [the EAS Build docs](https://docs.expo.dev/build/introduction/) for more information.
If you want to use EAS Build with a project not based on this template, see [this PR](https://github.com/PEZ/rn-rf-shadow/pull/24) for information about how your project can be set up to avoid an error during the build process.
Note: The `eas-build-pre-install.sh` script makes EAS install Java in the MacOS environment when running a build for iOS. This ensures that shadow-cljs can be run in the EAS pipeline to build your ClojureScript code.
## React Navigation included
The app is setup to use [React Navigation](https://reactnavigation.org/). If you don't need that in your app, just remove it.
## Happy Hacking! ❤️
Please don't hesitate to star the project repository.
+32
View File
@@ -0,0 +1,32 @@
{
"expo": {
"name": "Todo App",
"slug": "todo-expo",
"privacy": "public",
"platforms": [
"ios",
"android",
"web"
],
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"plugins": [
"expo-sqlite"
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

+7
View File
@@ -0,0 +1,7 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'],
};
};
+28
View File
@@ -0,0 +1,28 @@
{:paths ["src/main" "src/test"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
org.clojure/clojurescript {:mvn/version "1.11.60"}
;; React and Re-frame
reagent/reagent {:mvn/version "1.2.0"}
re-frame/re-frame {:mvn/version "1.3.0"}
day8.re-frame/http-fx {:mvn/version "0.2.4"}
day8.re-frame/tracing {:mvn/version "0.6.2"}}
:aliases
{:dev {:extra-deps {thheller/shadow-cljs {:mvn/version "2.28.10"}
nrepl/nrepl {:mvn/version "1.1.0"}
cider/cider-nrepl {:mvn/version "0.45.0"}}}
;; Shadow-cljs build
:shadow {:main-opts ["-m" "shadow.cljs.devtools.cli"]}
;; For connecting via MCP from pez-client side
:mcp-client {:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}
com.bhauman/clojure-mcp {:git/url "https://github.com/bhauman/clojure-mcp.git"
:git/tag "v0.1.8-alpha"
:git/sha "457f197"}}
:exec-fn clojure-mcp.main/start-mcp-server
:exec-args {:port 7892 ; Different port for pez-client REPL
:type :shadow-cljs
:shadow-build "app"}}}}
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# If the OS is MacOS, install Java so that the shadow-cljs build succeeds
if [[ $OSTYPE == "darwin"* ]]; then
brew install openjdk@11
sudo ln -sfn /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk || { echo 'Homebrew JDK 11 not found?' ; exit 1; }
echo 'export PATH="/opt/homebrew/opt/openjdk@11/bin:$PATH"' >>~/.zshrc
export CPPFLAGS="-I/opt/homebrew/opt/openjdk@11/include"
fi
+12
View File
@@ -0,0 +1,12 @@
--- worker.js 2018-11-21 14:46:01.271844624 -0700
+++ worker.js 2018-11-21 14:45:52.517615272 -0700
@@ -218,7 +218,7 @@
}
if (!options.transformOptions.dev) {
- plugins.push([constantFoldingPlugin, opts]);
+ // plugins.push([constantFoldingPlugin, opts]);
plugins.push([inlinePlugin, opts]);
}var _transformFromAstSync = transformFromAstSync(ast, "", {
ast: true,
babelrc: false,
+117
View File
@@ -0,0 +1,117 @@
#!/Usr/bin/env joker
;; Usage: toolchain-report
;;
;; This tool queries a set of defined packages in your "toolchain" and
;; reports the versions of those packages in a map. There are no
;; command line flags or options for this script.
(ns main
(:require [joker.os :as os]))
;; The "toolchain" is defined as a vector of maps that define how to
;; query for version. We expect every tool has some command line flag
;; that writes the version info to stdout or stderr, but each tool
;; might format that output in some unique way. Therefore we specify a
;; regular expression pattern that will be used to extract the version
;; from the output.
;;
;; Easiest to show an example:
;;
;; {
;; :key :yarn ; each tool has a unique key
;; :cmd ["yarn" "-v"] ; executing this prints the version
;; :pattern #"(.*)\n" ; this regexp extracts the version #
;; :output :out ; :out = stdout, :err = stderr
;; }
;;
;; The default is to grab everything from stdout up to the first
;; newline '\n', so our example can be shortened:
;;
;; {:key :yarn :cmd ["yarn" "-v"]}
;;
(def toolchain
[
;; operating system
{:key :os-name
:cmd ["clojure" "-e" "(System/getProperty \"os.name\")"]
:pattern #"\"(.*)\""}
{:key :os-version
:cmd ["clojure" "-e" "(System/getProperty \"os.version\")"]
:pattern #"\"(.*)\""}
{:key :todays-date
:cmd ["clojure" "-e" "(.toString (java.time.LocalDate/now))"]}
;; clojure/clojurescript tools
{:key :clojure
:cmd ["clj" "-Stree"]
:pattern #"org.clojure/clojure\s+(.*)\n"}
{:key :clojurescript
:cmd ["clj" "-Stree"]
:pattern #"org.clojure/clojurescript\s+(.*)\n"}
{:key :shadow-cljs-jar
:cmd ["shadow-cljs" "info"]
:pattern #"jar:\s+(.*)\n"}
{:key :shadow-cljs-cli
:cmd ["shadow-cljs" "info"]
:pattern #"cli:\s+(.*)\n"}
;; react native toolchain
{:key :expo-cli :cmd ["expo-cli" "-V"]}
;; javascript tools
{:key :node :cmd ["node" "-v"]}
{:key :yarn :cmd ["yarn" "-v"]}
;; libraries / packages
{:key :expo-js
:cmd ["yarn" "list"]
:pattern #"\s+expo@(.*)\n"}
{:key :react
:cmd ["yarn" "list"]
:pattern #"\s+react@(.*)\n"}
{:key :react-native
:cmd ["yarn" "list"]
:pattern #"\s+react-native@(.*)\n"}
{:key :reagent
:cmd ["clj" "-Stree"]
:pattern #"reagent/reagent\s+(.*)\n"}
{:key :re-frame
:cmd ["clj" "-Stree"]
:pattern #"re-frame/re-frame\s+(.*)\n"}
;; java jdk
{:key :jdk-vendor
:cmd ["java" "-version"]
:output :err
:pattern #"(.*)\s+version"}
{:key :jdk-version
:cmd ["java" "-version"]
:output :err
:pattern #"version\s+\"(.*)\"\n"}
])
(def sh-memoized (memoize #(apply os/sh %)))
(defn check [{:keys [key cmd output pattern]
:or {output :out pattern #"(.*)\n"}}]
(let [result (try (sh-memoized cmd)
(catch Error e {:success nil}))]
(if (:success result)
{key (-> (re-find pattern (output result))
(get 1))}
{key nil})))
(defn print-sorted-keys [m]
;; hack because joker doesn't provide sorted-map
(println "{")
(doseq [k (sort (keys m))]
(printf " %s \"%s\"\n" k (k m)))
(println "}"))
;; run all queries and print the result
(print-sorted-keys (->> (map check toolchain)
(apply merge)))
+5
View File
@@ -0,0 +1,5 @@
# fulcro doesn't properly type hint these since they are usually covered
# by react externs. we are not processing any JS however so those are missing
render
props
state
+42
View File
@@ -0,0 +1,42 @@
// Disable all Expo/Metro hot reload mechanisms BEFORE loading app
// This ensures only shadow-cljs hot reload remains active
if (typeof window !== 'undefined') {
// Disable React Fast Refresh
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => type => type;
// Disable Metro hot update
window.metroHotUpdateModule = () => {};
window.__accept = () => {};
// Disable webpack hot update (fallback)
window.webpackHotUpdate = () => {};
// Override WebSocket to block Metro connections
// const OriginalWebSocket = window.WebSocket;
// window.WebSocket = function(url) {
// if (url && (url.includes('metro') ||
// url.includes('packager') ||
// url.includes('19001') ||
// url.includes('19000') ||
// url.includes('8081'))) {
// console.log('Blocked Metro WebSocket connection:', url);
// return {
// send: () => {},
// close: () => {},
// addEventListener: () => {},
// removeEventListener: () => {}
// };
// }
// return new OriginalWebSocket(url);
// };
// Prevent module.hot usage
if (typeof module !== 'undefined' && module.hot) {
delete module.hot;
}
console.log('Expo/Metro hot reload disabled - shadow-cljs will handle hot reload');
}
import './app/index.js';
+20612
View File
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
{
"scripts": {
"server": "npx shadow-cljs server",
"start": "npx expo start",
"android": "npx expo start --android",
"ios": "npx expo start --ios",
"web": "npx expo start --web",
"web-only": "npx expo start --web-only",
"release": "npx shadow-cljs release app",
"eject": "npx expo eject",
"eas-build-pre-install": "bash eas-build-pre-install.sh",
"eas-build-post-install": "npx shadow-cljs release app"
},
"dependencies": {
"@expo/vector-icons": "^15.0.2",
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"create-react-class": "^15.7.0",
"expo": "^55.0.2",
"expo-cli": "^6.3.8",
"expo-sqlite": "~55.0.10",
"expo-status-bar": "~55.0.4",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-native": "0.83.2",
"react-native-gesture-handler": "~2.30.0",
"react-native-reanimated": "4.2.1",
"react-native-safe-area-context": "~5.6.2",
"react-native-screens": "~4.23.0",
"react-native-web": "^0.21.0"
},
"devDependencies": {
"shadow-cljs": "^2.23.3"
},
"private": true
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

+10
View File
@@ -0,0 +1,10 @@
{:source-paths ["src/main"]
:dependencies [[reagent "1.2.0"]
[re-frame "1.3.0"]]
:builds {:app {:target :react-native
:init-fn todo.app/init
:output-dir "app"
:compiler-options {:infer-externs :auto}
:devtools {:autoload true}}}}
+32
View File
@@ -0,0 +1,32 @@
(ns expo.root
(:require
["expo" :as expo]
["create-react-class" :as crc]))
(defonce root-ref (atom nil))
(defonce root-component-ref (atom nil))
(defn render-root [root]
(let [first-call? (nil? @root-ref)]
(reset! root-ref root)
(if-not first-call?
(when-let [root @root-component-ref]
(.forceUpdate ^js root))
(let [Root
(crc
#js {:componentDidMount
(fn []
(this-as this
(reset! root-component-ref this)))
:componentWillUnmount
(fn []
(reset! root-component-ref nil))
:render
(fn []
(let [body @root-ref]
(if (fn? body)
(body)
body)))})]
(expo/registerRootComponent Root)))))
+27
View File
@@ -0,0 +1,27 @@
(ns todo.app
(:require [reagent.core :as r]
[re-frame.core :as rf]
["react-native" :as rn]
["react-native-gesture-handler" :refer [GestureHandlerRootView]]
[expo.root :as expo-root]
[todo.events]
[todo.subs]
[todo.views.main :as main]
[todo.views.add-todo :as add-todo]))
(defn root []
(let [show-form? @(rf/subscribe [:show-form?])]
[:> GestureHandlerRootView {:style {:flex 1}}
[:> rn/StatusBar {:bar-style "light-content" :background-color "#6200EE"}]
[main/main-screen]
(when show-form?
[add-todo/add-todo-form])]))
(defn start
{:dev/after-load true}
[]
(expo-root/render-root (r/as-element [root])))
(defn init []
(rf/dispatch-sync [:initialize-db])
(start))
+14
View File
@@ -0,0 +1,14 @@
(ns todo.db)
(def categories ["Personal" "Work" "Shopping" "Health" "Other"])
(def priorities [{:key :low :label "Low" :color "#4CAF50"}
{:key :medium :label "Medium" :color "#FF9800"}
{:key :high :label "High" :color "#F44336"}])
(def default-db
{:todos {} ;; map of id -> todo
:filter :all ;; :all | :active | :completed
:next-temp-id -1 ;; for optimistic inserts before SQLite returns id
:editing-todo nil ;; nil or todo map being edited
:show-form? false}) ;; whether add/edit form is visible
+92
View File
@@ -0,0 +1,92 @@
(ns todo.events
(:require [clojure.string :as str]
[re-frame.core :as rf]
[todo.db :as db]
[todo.fx]))
(rf/reg-event-fx
:initialize-db
(fn [_ _]
{:db db/default-db
:sqlite/init true}))
(rf/reg-event-db
:todos-loaded
(fn [db [_ rows]]
(let [todos (->> rows
(map (fn [row]
(let [id (:id row)]
[id {:id id
:title (:title row)
:completed (= 1 (:completed row))
:category (:category row)
:priority (keyword (:priority row))
:created-at (:created_at row)}])))
(into {}))]
(assoc db :todos todos))))
(rf/reg-event-fx
:add-todo
(fn [{:keys [db]} [_ title category priority]]
(when (seq (str/trim (or title "")))
{:db (assoc db :show-form? false)
:sqlite/insert {:title (str/trim title)
:category category
:priority (name priority)
:on-success [:todo-inserted title category priority]}})))
(rf/reg-event-db
:todo-inserted
(fn [db [_ title category priority id]]
(assoc-in db [:todos id]
{:id id
:title (str/trim title)
:completed false
:category category
:priority (keyword priority)
:created-at (js/Math.floor (/ (.now js/Date) 1000))})))
(rf/reg-event-fx
:toggle-todo
(fn [{:keys [db]} [_ id]]
(let [todo (get-in db [:todos id])
new-completed (not (:completed todo))]
{:db (assoc-in db [:todos id :completed] new-completed)
:sqlite/toggle {:id id :completed new-completed}})))
(rf/reg-event-fx
:update-todo
(fn [{:keys [db]} [_ id title category priority]]
{:db (-> db
(assoc-in [:todos id :title] title)
(assoc-in [:todos id :category] category)
(assoc-in [:todos id :priority] priority)
(assoc :show-form? false
:editing-todo nil))
:sqlite/update {:id id :title title :category category :priority (name priority)}}))
(rf/reg-event-fx
:delete-todo
(fn [{:keys [db]} [_ id]]
{:db (update db :todos dissoc id)
:sqlite/delete {:id id}}))
(rf/reg-event-db
:set-filter
(fn [db [_ filter-val]]
(assoc db :filter filter-val)))
(rf/reg-event-db
:show-add-form
(fn [db _]
(assoc db :show-form? true :editing-todo nil)))
(rf/reg-event-db
:show-edit-form
(fn [db [_ todo]]
(assoc db :show-form? true :editing-todo todo)))
(rf/reg-event-db
:hide-form
(fn [db _]
(assoc db :show-form? false :editing-todo nil)))
+49
View File
@@ -0,0 +1,49 @@
(ns todo.fx
(:require [re-frame.core :as rf]
[todo.sqlite :as sqlite]))
(defonce db-instance (atom nil))
(rf/reg-fx
:sqlite/init
(fn [_]
(-> (sqlite/open-db)
(.then (fn [db]
(reset! db-instance db)
(-> (sqlite/init-db db)
(.then (fn [_]
(-> (sqlite/get-all-todos db)
(.then (fn [rows]
(rf/dispatch [:todos-loaded (js->clj rows :keywordize-keys true)])))))))))
(.catch (fn [err] (js/console.error "SQLite init error:" err))))))
(rf/reg-fx
:sqlite/insert
(fn [{:keys [title category priority on-success]}]
(when-let [db @db-instance]
(-> (sqlite/insert-todo db title category priority)
(.then (fn [result]
(when on-success
(rf/dispatch (conj on-success (.-lastInsertRowId ^js result))))))
(.catch (fn [err] (js/console.error "Insert error:" err)))))))
(rf/reg-fx
:sqlite/update
(fn [{:keys [id title category priority]}]
(when-let [db @db-instance]
(-> (sqlite/update-todo-title db id title category priority)
(.catch (fn [err] (js/console.error "Update error:" err)))))))
(rf/reg-fx
:sqlite/toggle
(fn [{:keys [id completed]}]
(when-let [db @db-instance]
(-> (sqlite/toggle-todo db id completed)
(.catch (fn [err] (js/console.error "Toggle error:" err)))))))
(rf/reg-fx
:sqlite/delete
(fn [{:keys [id]}]
(when-let [db @db-instance]
(-> (sqlite/delete-todo db id)
(.catch (fn [err] (js/console.error "Delete error:" err)))))))
+39
View File
@@ -0,0 +1,39 @@
(ns todo.sqlite
(:require ["expo-sqlite" :as SQLite]))
(defn open-db []
(SQLite/openDatabaseAsync "todos.db"))
(defn init-db [^js db]
(.execAsync db
"CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER DEFAULT 0,
category TEXT DEFAULT 'Personal',
priority TEXT DEFAULT 'medium',
created_at INTEGER DEFAULT (strftime('%s','now'))
);"))
(defn get-all-todos [^js db]
(.getAllAsync db "SELECT * FROM todos ORDER BY created_at DESC"))
(defn insert-todo [^js db title category priority]
(.runAsync db
"INSERT INTO todos (title, category, priority) VALUES (?, ?, ?)"
#js [title category priority]))
(defn update-todo-title [^js db id title category priority]
(.runAsync db
"UPDATE todos SET title = ?, category = ?, priority = ? WHERE id = ?"
#js [title category priority id]))
(defn toggle-todo [^js db id completed]
(.runAsync db
"UPDATE todos SET completed = ? WHERE id = ?"
#js [(if completed 1 0) id]))
(defn delete-todo [^js db id]
(.runAsync db
"DELETE FROM todos WHERE id = ?"
#js [id]))
+27
View File
@@ -0,0 +1,27 @@
(ns todo.subs
(:require [re-frame.core :as rf]))
(rf/reg-sub :todos (fn [db _] (:todos db)))
(rf/reg-sub :filter (fn [db _] (:filter db)))
(rf/reg-sub :show-form? (fn [db _] (:show-form? db)))
(rf/reg-sub :editing-todo (fn [db _] (:editing-todo db)))
(rf/reg-sub
:filtered-todos
:<- [:todos]
:<- [:filter]
(fn [[todos filter-val] _]
(let [todo-list (sort-by :created-at > (vals todos))]
(case filter-val
:all todo-list
:active (filter #(not (:completed %)) todo-list)
:completed (filter :completed todo-list)))))
(rf/reg-sub
:todo-counts
:<- [:todos]
(fn [todos _]
(let [all (vals todos)]
{:all (count all)
:active (count (filter #(not (:completed %)) all))
:completed (count (filter :completed all))})))
+24
View File
@@ -0,0 +1,24 @@
(ns todo.theme)
(def colors
{:primary "#6200EE"
:primary-dark "#3700B3"
:secondary "#03DAC6"
:background "#F5F5F5"
:surface "#FFFFFF"
:error "#B00020"
:on-primary "#FFFFFF"
:on-surface "#000000"
:on-background "#000000"
:text-secondary "#666666"
:border "#E0E0E0"
:completed-text "#999999"
:completed-bg "#F0F0F0"})
(def spacing
{:xs 4 :sm 8 :md 16 :lg 24 :xl 32})
(def priority-colors
{:low "#4CAF50"
:medium "#FF9800"
:high "#F44336"})
@@ -0,0 +1,65 @@
(ns todo.views.add-todo
(:require [clojure.string :as str]
[reagent.core :as r]
["react-native" :as rn]
[re-frame.core :as rf]
[todo.theme :as theme]
[todo.views.category-picker :as picker]))
(defn add-todo-form []
(let [editing @(rf/subscribe [:editing-todo])
title (r/atom (or (:title editing) ""))
category (r/atom (or (:category editing) "Personal"))
priority (r/atom (or (:priority editing) :medium))]
(fn []
[:> rn/View {:style {:position "absolute" :top 0 :left 0 :right 0 :bottom 0
:background-color "rgba(0,0,0,0.5)"
:justify-content "center"
:padding 24}}
[:> rn/View {:style {:background-color (:surface theme/colors)
:border-radius 16
:padding 24
:elevation 8}}
[:> rn/Text {:style {:font-size 20 :font-weight "bold" :margin-bottom 16
:color (:on-surface theme/colors)}}
(if editing "Edit Todo" "Add New Todo")]
[:> rn/TextInput
{:style {:border-width 1 :border-color (:border theme/colors)
:border-radius 8 :padding 12 :font-size 16
:margin-bottom 16}
:placeholder "What needs to be done?"
:placeholder-text-color (:text-secondary theme/colors)
:value @title
:on-change-text #(reset! title %)
:auto-focus true}]
[:> rn/Text {:style {:font-size 14 :font-weight "600" :color (:text-secondary theme/colors)
:margin-bottom 4}}
"Category"]
[picker/category-picker @category #(reset! category %)]
[:> rn/Text {:style {:font-size 14 :font-weight "600" :color (:text-secondary theme/colors)
:margin-bottom 4 :margin-top 8}}
"Priority"]
[picker/priority-picker @priority #(reset! priority %)]
[:> rn/View {:style {:flex-direction "row" :justify-content "flex-end"
:gap 12 :margin-top 24}}
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:hide-form])
:style {:padding-horizontal 20 :padding-vertical 10
:border-radius 8}}
[:> rn/Text {:style {:color (:text-secondary theme/colors) :font-size 16}} "Cancel"]]
[:> rn/TouchableOpacity
{:on-press (fn []
(when (seq (str/trim @title))
(if editing
(rf/dispatch [:update-todo (:id editing) @title @category @priority])
(rf/dispatch [:add-todo @title @category @priority]))))
:style {:padding-horizontal 20 :padding-vertical 10
:border-radius 8
:background-color (:primary theme/colors)}}
[:> rn/Text {:style {:color (:on-primary theme/colors) :font-size 16 :font-weight "600"}}
(if editing "Save" "Add")]]]]])))
@@ -0,0 +1,40 @@
(ns todo.views.category-picker
(:require [reagent.core :as r]
["react-native" :as rn]
[todo.db :as db]
[todo.theme :as theme]))
(defn category-picker [selected on-select]
[:> rn/View {:style {:flex-direction "row" :flex-wrap "wrap" :gap 8 :margin-vertical 8}}
(for [cat db/categories]
^{:key cat}
[:> rn/TouchableOpacity
{:on-press #(on-select cat)
:style {:padding-horizontal 16
:padding-vertical 8
:border-radius 20
:background-color (if (= cat selected)
(:primary theme/colors)
(:border theme/colors))}}
[:> rn/Text {:style {:color (if (= cat selected)
(:on-primary theme/colors)
(:on-surface theme/colors))
:font-size 14}}
cat]])])
(defn priority-picker [selected on-select]
[:> rn/View {:style {:flex-direction "row" :gap 8 :margin-vertical 8}}
(for [{:keys [key label color]} db/priorities]
^{:key key}
[:> rn/TouchableOpacity
{:on-press #(on-select key)
:style {:padding-horizontal 16
:padding-vertical 8
:border-radius 20
:border-width 2
:border-color color
:background-color (if (= key selected) color "transparent")}}
[:> rn/Text {:style {:color (if (= key selected) "#FFFFFF" color)
:font-weight "600"
:font-size 14}}
label]])])
+72
View File
@@ -0,0 +1,72 @@
(ns todo.views.main
(:require [reagent.core :as r]
["react-native" :as rn]
[re-frame.core :as rf]
[todo.theme :as theme]
[todo.views.todo-item :as todo-item]))
(defn filter-bar []
(let [current-filter @(rf/subscribe [:filter])
counts @(rf/subscribe [:todo-counts])]
[:> rn/View {:style {:flex-direction "row" :padding-horizontal 16
:padding-vertical 8 :gap 8}}
(for [[filter-key label] [[:all "All"] [:active "Active"] [:completed "Done"]]]
^{:key filter-key}
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:set-filter filter-key])
:style {:padding-horizontal 16 :padding-vertical 8
:border-radius 20
:background-color (if (= current-filter filter-key)
(:primary theme/colors)
(:border theme/colors))}}
[:> rn/Text {:style {:color (if (= current-filter filter-key)
(:on-primary theme/colors)
(:text-secondary theme/colors))
:font-weight "600"}}
(str label " (" (get counts filter-key 0) ")")]])]))
(defn empty-state []
[:> rn/View {:style {:flex 1 :justify-content "center" :align-items "center" :padding 48}}
[:> rn/Text {:style {:font-size 48 :margin-bottom 16}} "\uD83D\uDCDD"]
[:> rn/Text {:style {:font-size 18 :color (:text-secondary theme/colors)
:text-align "center"}}
"No todos yet!\nTap + to add one"]])
(defn todo-list []
(let [todos @(rf/subscribe [:filtered-todos])]
(if (empty? todos)
[empty-state]
[:> rn/FlatList
{:data (clj->js (map #(assoc % :key (str (:id %))) todos))
:render-item (fn [^js item]
(let [data (js->clj (.-item item) :keywordize-keys true)
data (update data :priority keyword)]
(r/as-element [todo-item/todo-item data])))
:key-extractor (fn [^js item] (str (.-id item)))
:content-container-style {:padding-bottom 100}}])))
(defn fab []
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:show-add-form])
:style {:position "absolute"
:right 24 :bottom 32
:width 56 :height 56 :border-radius 28
:background-color (:primary theme/colors)
:justify-content "center" :align-items "center"
:elevation 6
:shadow-color "#000"
:shadow-offset {:width 0 :height 3}
:shadow-opacity 0.3
:shadow-radius 4}}
[:> rn/Text {:style {:color "#FFFFFF" :font-size 28 :line-height 30}} "+"]])
(defn main-screen []
[:> rn/View {:style {:flex 1 :background-color (:background theme/colors)}}
;; Header
[:> rn/View {:style {:background-color (:primary theme/colors)
:padding-top 48 :padding-bottom 16 :padding-horizontal 24}}
[:> rn/Text {:style {:font-size 28 :font-weight "bold" :color (:on-primary theme/colors)}}
"My Todos"]]
[filter-bar]
[todo-list]
[fab]])
@@ -0,0 +1,64 @@
(ns todo.views.todo-item
(:require [reagent.core :as r]
["react-native" :as rn]
["react-native-gesture-handler" :refer [Swipeable]]
[re-frame.core :as rf]
[todo.theme :as theme]))
(defn render-right-actions [id]
(fn [_progress _drag-x]
(r/as-element
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:delete-todo id])
:style {:background-color (:error theme/colors)
:justify-content "center"
:align-items "center"
:width 80
:border-radius 12
:margin-vertical 4
:margin-right 16}}
[:> rn/Text {:style {:color "#FFFFFF" :font-weight "bold" :font-size 14}} "Delete"]])))
(defn todo-item [{:keys [id title completed category priority]}]
[:> Swipeable {:render-right-actions (render-right-actions id)
:overshoot-right false}
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:show-edit-form {:id id :title title :completed completed
:category category :priority priority}])
:active-opacity 0.7
:style {:flex-direction "row"
:align-items "center"
:background-color (if completed (:completed-bg theme/colors) (:surface theme/colors))
:margin-horizontal 16
:margin-vertical 4
:padding 16
:border-radius 12
:elevation 2
:shadow-color "#000"
:shadow-offset {:width 0 :height 1}
:shadow-opacity 0.1
:shadow-radius 2}}
[:> rn/TouchableOpacity
{:on-press #(rf/dispatch [:toggle-todo id])
:style {:width 28 :height 28 :border-radius 14
:border-width 2
:border-color (if completed (:primary theme/colors) (:border theme/colors))
:background-color (if completed (:primary theme/colors) "transparent")
:justify-content "center" :align-items "center"
:margin-right 12}}
(when completed
[:> rn/Text {:style {:color "#FFFFFF" :font-size 16}} "\u2713"])]
[:> rn/View {:style {:flex 1}}
[:> rn/Text {:style {:font-size 16
:color (if completed (:completed-text theme/colors) (:on-surface theme/colors))
:text-decoration-line (if completed "line-through" "none")}}
title]
[:> rn/View {:style {:flex-direction "row" :align-items "center" :margin-top 4 :gap 8}}
[:> rn/View {:style {:background-color (:border theme/colors)
:padding-horizontal 8 :padding-vertical 2
:border-radius 10}}
[:> rn/Text {:style {:font-size 12 :color (:text-secondary theme/colors)}} category]]
[:> rn/View {:style {:width 10 :height 10 :border-radius 5
:background-color (get theme/priority-colors priority "#999")}}]]]]])
+3
View File
@@ -0,0 +1,3 @@
# Syntax highlighting for ClojureDart files
*.cljd linguist-language=Clojure
+51
View File
@@ -0,0 +1,51 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# ClojureDart
.cpcache/
.clojuredart/
lib/cljd-out/
test/cljd-out/
+45
View File
@@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "d8a9f9a52e5af486f80d932e838ee93861ffd863"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: android
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: ios
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: linux
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: macos
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: web
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: windows
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
+16
View File
@@ -0,0 +1,16 @@
# cljd_todo_flutter
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
+28
View File
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
+13
View File
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
+44
View File
@@ -0,0 +1,44 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
android {
namespace = "com.example.cljd_todo_flutter"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.cljd_todo_flutter"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
}
}
flutter {
source = "../.."
}
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
@@ -0,0 +1,45 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="cljd_todo_flutter"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
@@ -0,0 +1,5 @@
package com.example.cljd_todo_flutter
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+18
View File
@@ -0,0 +1,18 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+3
View File
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
+25
View File
@@ -0,0 +1,25 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.2.1" apply false
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
}
include ":app"
+7
View File
@@ -0,0 +1,7 @@
{:paths ["src"]
:deps {tensegritics/clojuredart
{:git/url "https://github.com/tensegritics/ClojureDart.git"
:sha "0375b3d0e0dfcd5ca5c97f2148124cb7e0d0a7d3"}}
:aliases {:cljd {:main-opts ["-m" "cljd.build"]}}
:cljd/opts {:kind :flutter
:main todo.main}}
+34
View File
@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
+1
View File
@@ -0,0 +1 @@
#include "Generated.xcconfig"
@@ -0,0 +1 @@
#include "Generated.xcconfig"
@@ -0,0 +1,616 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.cljdTodoFlutter;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
+13
View File
@@ -0,0 +1,13 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
@@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Cljd Todo Flutter</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>cljd_todo_flutter</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
@@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"
@@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
+1
View File
@@ -0,0 +1 @@
export "cljd-out/todo/main.dart" show main;

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