This commit is contained in:
lokeshramchand-ctrl 2025-07-31 13:38:35 +05:30
parent c0548e67bc
commit 4b2f7ac3b6
100 changed files with 4954 additions and 375 deletions

View file

@ -1 +1,4 @@
MONGO_URI=mongodb://localhost:27017/chat
HOST=0.0.0.0
PORT=3000
CORS_ORIGIN=http://10.231.59.78:3000

View file

@ -1,11 +1,14 @@
require('dotenv').config(); // Add this at the very top
const express = require('express');
const mongoose = require('mongoose');
const axios = require('axios');
const cors = require('cors');
const app = express();
app.use(express.json()); // to parse JSON
app.use(cors({
origin: process.env.CORS_ORIGIN || '*'
}));
// Prediction route
const predictRoute = require('./predict');
app.use('/api/predict', predictRoute);
@ -33,7 +36,7 @@ app.post('/api/transaction/add', async (req, res) => {
const { description, amount } = req.body;
// Call your AI prediction endpoint
const predictRes = await axios.post('http://192.168.1.9:5000/api/predict', {
const predictRes = await axios.post('http://10.231.12.247:5000/api/predict', {
description,
});
@ -114,8 +117,9 @@ app.get('/api/transactions/recent', async (req, res) => {
}
});
// Start server
app.listen(3000, () => {
console.log('🚀 Server running on port 3000');
const HOST = process.env.HOST || '0.0.0.0'; // listen on all interfaces
const PORT = process.env.PORT || 3000;
app.listen(PORT, HOST, () => {
console.log(`🚀 Server running on http://${HOST}:${PORT}`);
});

View file

@ -176,6 +176,19 @@
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@ -212,9 +225,9 @@
}
},
"node_modules/dotenv": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.0.0.tgz",
"integrity": "sha512-A0BJ5lrpJVSfnMMXjmeO0xUnoxqsBHWCoqqTnGwGYVdnctqXXUEhJOO7LxmgxJon9tEZFGpe0xPRX0h2v3AANQ==",
"version": "17.2.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
"integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@ -392,14 +405,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@ -771,6 +785,15 @@
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",

33
Backend/node_modules/cors/CONTRIBUTING.md generated vendored Normal file
View file

@ -0,0 +1,33 @@
# contributing to `cors`
CORS is a node.js package for providing a [connect](http://www.senchalabs.org/connect/)/[express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. Learn more about the project in [the README](README.md).
## The CORS Spec
[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/)
## Pull Requests Welcome
* Include `'use strict';` in every javascript file.
* 2 space indentation.
* Please run the testing steps below before submitting.
## Testing
```bash
$ npm install
$ npm test
```
## Interactive Testing Harness
[http://node-cors-client.herokuapp.com](http://node-cors-client.herokuapp.com)
Related git repositories:
* [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
* [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
## License
[MIT License](http://www.opensource.org/licenses/mit-license.php)

58
Backend/node_modules/cors/HISTORY.md generated vendored Normal file
View file

@ -0,0 +1,58 @@
2.8.5 / 2018-11-04
==================
* Fix setting `maxAge` option to `0`
2.8.4 / 2017-07-12
==================
* Work-around Safari bug in default pre-flight response
2.8.3 / 2017-03-29
==================
* Fix error when options delegate missing `methods` option
2.8.2 / 2017-03-28
==================
* Fix error when frozen options are passed
* Send "Vary: Origin" when using regular expressions
* Send "Vary: Access-Control-Request-Headers" when dynamic `allowedHeaders`
2.8.1 / 2016-09-08
==================
This release only changed documentation.
2.8.0 / 2016-08-23
==================
* Add `optionsSuccessStatus` option
2.7.2 / 2016-08-23
==================
* Fix error when Node.js running in strict mode
2.7.1 / 2015-05-28
==================
* Move module into expressjs organization
2.7.0 / 2015-05-28
==================
* Allow array of matching condition as `origin` option
* Allow regular expression as `origin` option
2.6.1 / 2015-05-28
==================
* Update `license` in package.json
2.6.0 / 2015-04-27
==================
* Add `preflightContinue` option
* Fix "Vary: Origin" header added for "*"

22
Backend/node_modules/cors/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2013 Troy Goode <troygoode@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

243
Backend/node_modules/cors/README.md generated vendored Normal file
View file

@ -0,0 +1,243 @@
# cors
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
CORS is a node.js package for providing a [Connect](http://www.senchalabs.org/connect/)/[Express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options.
**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)**
* [Installation](#installation)
* [Usage](#usage)
* [Simple Usage](#simple-usage-enable-all-cors-requests)
* [Enable CORS for a Single Route](#enable-cors-for-a-single-route)
* [Configuring CORS](#configuring-cors)
* [Configuring CORS Asynchronously](#configuring-cors-asynchronously)
* [Enabling CORS Pre-Flight](#enabling-cors-pre-flight)
* [Configuration Options](#configuration-options)
* [Demo](#demo)
* [License](#license)
* [Author](#author)
## Installation
This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/). Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
```sh
$ npm install cors
```
## Usage
### Simple Usage (Enable *All* CORS Requests)
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Enable CORS for a Single Route
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.get('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a Single Route'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Configuring CORS
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Configuring CORS w/ Dynamic Origin
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
If you do not want to block REST tools or server-to-server requests,
add a `!origin` check in the origin function like so:
```javascript
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
```
### Enabling CORS Pre-Flight
Certain CORS requests are considered 'complex' and require an initial
`OPTIONS` request (called the "pre-flight request"). An example of a
'complex' CORS request is one that uses an HTTP verb other than
GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable
pre-flighting, you must add a new OPTIONS handler for the route you want
to support:
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
app.del('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
You can also enable pre-flight across-the-board like so:
```javascript
app.options('*', cors()) // include before other routes
```
### Configuring CORS Asynchronously
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
} else {
corsOptions = { origin: false } // disable CORS for this request
}
callback(null, corsOptions) // callback expects two parameters: error and options
}
app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
## Configuration Options
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values:
- `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS.
- `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed.
- `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (which expects the signature `err [object], allow [bool]`) as the second.
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted.
* `preflightContinue`: Pass the CORS preflight response to the next handler.
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
The default configuration is the equivalent of:
```json
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
```
For details on the effect of each CORS header, read [this](http://www.html5rocks.com/en/tutorials/cors/) article on HTML5 Rocks.
## Demo
A demo that illustrates CORS working (and not working) using jQuery is available here: [http://node-cors-client.herokuapp.com/](http://node-cors-client.herokuapp.com/)
Code for that demo can be found here:
* Client: [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
* Server: [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
## License
[MIT License](http://www.opensource.org/licenses/mit-license.php)
## Author
[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com))
[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg
[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master
[downloads-image]: https://img.shields.io/npm/dm/cors.svg
[downloads-url]: https://npmjs.org/package/cors
[npm-image]: https://img.shields.io/npm/v/cors.svg
[npm-url]: https://npmjs.org/package/cors
[travis-image]: https://img.shields.io/travis/expressjs/cors/master.svg
[travis-url]: https://travis-ci.org/expressjs/cors

238
Backend/node_modules/cors/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,238 @@
(function () {
'use strict';
var assign = require('object-assign');
var vary = require('vary');
var defaults = {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 204
};
function isString(s) {
return typeof s === 'string' || s instanceof String;
}
function isOriginAllowed(origin, allowedOrigin) {
if (Array.isArray(allowedOrigin)) {
for (var i = 0; i < allowedOrigin.length; ++i) {
if (isOriginAllowed(origin, allowedOrigin[i])) {
return true;
}
}
return false;
} else if (isString(allowedOrigin)) {
return origin === allowedOrigin;
} else if (allowedOrigin instanceof RegExp) {
return allowedOrigin.test(origin);
} else {
return !!allowedOrigin;
}
}
function configureOrigin(options, req) {
var requestOrigin = req.headers.origin,
headers = [],
isAllowed;
if (!options.origin || options.origin === '*') {
// allow any origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: '*'
}]);
} else if (isString(options.origin)) {
// fixed origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: options.origin
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
} else {
isAllowed = isOriginAllowed(requestOrigin, options.origin);
// reflect origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: isAllowed ? requestOrigin : false
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
}
return headers;
}
function configureMethods(options) {
var methods = options.methods;
if (methods.join) {
methods = options.methods.join(','); // .methods is an array, so turn it into a string
}
return {
key: 'Access-Control-Allow-Methods',
value: methods
};
}
function configureCredentials(options) {
if (options.credentials === true) {
return {
key: 'Access-Control-Allow-Credentials',
value: 'true'
};
}
return null;
}
function configureAllowedHeaders(options, req) {
var allowedHeaders = options.allowedHeaders || options.headers;
var headers = [];
if (!allowedHeaders) {
allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers
headers.push([{
key: 'Vary',
value: 'Access-Control-Request-Headers'
}]);
} else if (allowedHeaders.join) {
allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string
}
if (allowedHeaders && allowedHeaders.length) {
headers.push([{
key: 'Access-Control-Allow-Headers',
value: allowedHeaders
}]);
}
return headers;
}
function configureExposedHeaders(options) {
var headers = options.exposedHeaders;
if (!headers) {
return null;
} else if (headers.join) {
headers = headers.join(','); // .headers is an array, so turn it into a string
}
if (headers && headers.length) {
return {
key: 'Access-Control-Expose-Headers',
value: headers
};
}
return null;
}
function configureMaxAge(options) {
var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()
if (maxAge && maxAge.length) {
return {
key: 'Access-Control-Max-Age',
value: maxAge
};
}
return null;
}
function applyHeaders(headers, res) {
for (var i = 0, n = headers.length; i < n; i++) {
var header = headers[i];
if (header) {
if (Array.isArray(header)) {
applyHeaders(header, res);
} else if (header.key === 'Vary' && header.value) {
vary(res, header.value);
} else if (header.value) {
res.setHeader(header.key, header.value);
}
}
}
}
function cors(options, req, res, next) {
var headers = [],
method = req.method && req.method.toUpperCase && req.method.toUpperCase();
if (method === 'OPTIONS') {
// preflight
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureMethods(options, req));
headers.push(configureAllowedHeaders(options, req));
headers.push(configureMaxAge(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res);
if (options.preflightContinue) {
next();
} else {
// Safari (and potentially other browsers) need content-length 0,
// for 204 or they just hang waiting for a body
res.statusCode = options.optionsSuccessStatus;
res.setHeader('Content-Length', '0');
res.end();
}
} else {
// actual response
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res);
next();
}
}
function middlewareWrapper(o) {
// if options are static (either via defaults or custom options passed in), wrap in a function
var optionsCallback = null;
if (typeof o === 'function') {
optionsCallback = o;
} else {
optionsCallback = function (req, cb) {
cb(null, o);
};
}
return function corsMiddleware(req, res, next) {
optionsCallback(req, function (err, options) {
if (err) {
next(err);
} else {
var corsOptions = assign({}, defaults, options);
var originCallback = null;
if (corsOptions.origin && typeof corsOptions.origin === 'function') {
originCallback = corsOptions.origin;
} else if (corsOptions.origin) {
originCallback = function (origin, cb) {
cb(null, corsOptions.origin);
};
}
if (originCallback) {
originCallback(req.headers.origin, function (err2, origin) {
if (err2 || !origin) {
next(err2);
} else {
corsOptions.origin = origin;
cors(corsOptions, req, res, next);
}
});
} else {
next();
}
}
});
};
}
// can pass either an options hash, an options delegate, or nothing
module.exports = middlewareWrapper;
}());

41
Backend/node_modules/cors/package.json generated vendored Normal file
View file

@ -0,0 +1,41 @@
{
"name": "cors",
"description": "Node.js CORS middleware",
"version": "2.8.5",
"author": "Troy Goode <troygoode@gmail.com> (https://github.com/troygoode/)",
"license": "MIT",
"keywords": [
"cors",
"express",
"connect",
"middleware"
],
"repository": "expressjs/cors",
"main": "./lib/index.js",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"devDependencies": {
"after": "0.8.2",
"eslint": "2.13.1",
"express": "4.16.3",
"mocha": "5.2.0",
"nyc": "13.1.0",
"supertest": "3.3.0"
},
"files": [
"lib/index.js",
"CONTRIBUTING.md",
"HISTORY.md",
"LICENSE",
"README.md"
],
"engines": {
"node": ">= 0.10"
},
"scripts": {
"test": "npm run lint && nyc --reporter=html --reporter=text mocha --require test/support/env",
"lint": "eslint lib test"
}
}

View file

@ -2,13 +2,73 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [Unreleased](https://github.com/motdotla/dotenv/compare/v17.0.0...master)
## [Unreleased](https://github.com/motdotla/dotenv/compare/v17.2.1...master)
## [17.2.1](https://github.com/motdotla/dotenv/compare/v17.2.0...v17.2.1) (2025-07-24)
### Changed
* Fix clickable tip links by removing parentheses ([#897](https://github.com/motdotla/dotenv/pull/897))
## [17.2.0](https://github.com/motdotla/dotenv/compare/v17.1.0...v17.2.0) (2025-07-09)
### Added
* Optionally specify `DOTENV_CONFIG_QUIET=true` in your environment or `.env` file to quiet the runtime log ([#889](https://github.com/motdotla/dotenv/pull/889))
* Just like dotenv any `DOTENV_CONFIG_` environment variables take precedence over any code set options like `({quiet: false})`
```ini
# .env
DOTENV_CONFIG_QUIET=true
HELLO="World"
```
```js
// index.js
require('dotenv').config()
console.log(`Hello ${process.env.HELLO}`)
```
```sh
$ node index.js
Hello World
or
$ DOTENV_CONFIG_QUIET=true node index.js
```
## [17.1.0](https://github.com/motdotla/dotenv/compare/v17.0.1...v17.1.0) (2025-07-07)
### Added
* Add additional security and configuration tips to the runtime log ([#884](https://github.com/motdotla/dotenv/pull/884))
* Dim the tips text from the main injection information text
```js
const TIPS = [
'🔐 encrypt with dotenvx: https://dotenvx.com',
'🔐 prevent committing .env to code: https://dotenvx.com/precommit',
'🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
'🛠️ run anywhere with `dotenvx run -- yourcommand`',
'⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
'⚙️ enable debug logging with { debug: true }',
'⚙️ override existing env vars with { override: true }',
'⚙️ suppress all logs with { quiet: true }',
'⚙️ write to custom object with { processEnv: myObject }',
'⚙️ load multiple .env files with { path: [\'.env.local\', \'.env\'] }'
]
```
## [17.0.1](https://github.com/motdotla/dotenv/compare/v17.0.0...v17.0.1) (2025-07-01)
### Changed
* Patched injected log to count only populated/set keys to process.env ([#879](https://github.com/motdotla/dotenv/pull/879))
## [17.0.0](https://github.com/motdotla/dotenv/compare/v16.6.1...v17.0.0) (2025-06-27)
### Changed
- Default `quiet` to false - informational (file and keys count) runtime log message shows by default ([#875](https://github.com/motdotla/dotenv/pull/874))
- Default `quiet` to false - informational (file and keys count) runtime log message shows by default ([#875](https://github.com/motdotla/dotenv/pull/875))
## [16.6.1](https://github.com/motdotla/dotenv/compare/v16.6.0...v16.6.1) (2025-06-27)

View file

@ -4,25 +4,6 @@
&nbsp;
<div align="center">
<p>
<sup>
<a href="https://github.com/sponsors/motdotla">Dotenv es apoyado por la comunidad.</a>
</sup>
</p>
<sup>Gracias espaciales a:</sup>
<br>
<br>
<a href="https://graphite.dev/?utm_source=github&utm_medium=repo&utm_campaign=dotenv"><img src="https://res.cloudinary.com/dotenv-org/image/upload/v1744035073/graphite_lgsrl8.gif" width="240" alt="Graphite" /></a>
<a href="https://graphite.dev/?utm_source=github&utm_medium=repo&utm_campaign=dotenv">
<b>Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster.</b>
</a>
<hr>
</div>
# dotenv [![NPM version](https://img.shields.io/npm/v/dotenv.svg?style=flat-square)](https://www.npmjs.com/package/dotenv)
<img src="https://raw.githubusercontent.com/motdotla/dotenv/master/dotenv.svg" alt="dotenv" align="right" width="200" />

View file

@ -4,19 +4,6 @@
&nbsp;
<div align="center">
**Special thanks to [our sponsors](https://github.com/sponsors/motdotla)**
<br>
<a href="https://graphite.dev/?utm_source=github&utm_medium=repo&utm_campaign=dotenv"><img src="https://res.cloudinary.com/dotenv-org/image/upload/v1744035073/graphite_lgsrl8.gif" width="240" alt="Graphite" /></a>
<br>
<a href="https://graphite.dev/?utm_source=github&utm_medium=repo&utm_campaign=dotenv">
<b>Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster.</b>
</a>
<hr>
</div>
# dotenv [![NPM version](https://img.shields.io/npm/v/dotenv.svg?style=flat-square)](https://www.npmjs.com/package/dotenv)
<img src="https://raw.githubusercontent.com/motdotla/dotenv/master/dotenv.svg" alt="dotenv" align="right" width="200" />
@ -83,6 +70,14 @@ console.log(process.env) // remove this after you've confirmed it is working
import 'dotenv/config'
```
ES6 import if you need to set config options:
```javascript
import dotenv from 'dotenv'
dotenv.config({ path: '/custom/path/to/.env' })
```
That's it. `process.env` now has the keys and values you defined in your `.env` file:
```javascript
@ -165,7 +160,24 @@ $ DOTENV_CONFIG_ENCODING=latin1 DOTENV_CONFIG_DEBUG=true node -r dotenv/config y
### Variable Expansion
You need to add the value of another variable in one of your variables? Use [dotenv-expand](https://github.com/motdotla/dotenv-expand).
Use [dotenvx](https://github.com/dotenvx/dotenvx) to use variable expansion.
Reference and expand variables already on your machine for use in your .env file.
```ini
# .env
USERNAME="username"
DATABASE_URL="postgres://${USERNAME}@localhost/my_database"
```
```js
// index.js
console.log('DATABASE_URL', process.env.DATABASE_URL)
```
```sh
$ dotenvx run --debug -- node index.js
[dotenvx@0.14.1] injecting env (2) from .env
DATABASE_URL postgres://username@localhost/my_database
```
### Command Substitution
@ -272,7 +284,6 @@ Dotenv exposes four functions:
* `config`
* `parse`
* `populate`
* `decrypt`
### Config
@ -582,7 +593,7 @@ Does that make sense? It's a bit unintuitive, but it is how importing of ES6 mod
There are two alternatives to this approach:
1. Preload dotenv: `node --require dotenv/config index.js` (_Note: you do not need to `import` dotenv with this approach_)
1. Preload with dotenvx: `dotenvx run -- node index.js` (_Note: you do not need to `import` dotenv with this approach_)
2. Create a separate file that will execute `config` first as outlined in [this comment on #133](https://github.com/motdotla/dotenv/issues/133#issuecomment-255298822)
### Why am I getting the error `Module not found: Error: Can't resolve 'crypto|os|path'`?
@ -629,7 +640,7 @@ Try [dotenv-expand](https://github.com/motdotla/dotenv-expand)
### What about syncing and securing .env files?
Use [dotenvx](https://github.com/dotenvx/dotenvx)
Use [dotenvx](https://github.com/dotenvx/dotenvx) to unlock syncing encrypted .env files over git.
### What if I accidentally commit my `.env` file to code?

View file

@ -6,6 +6,10 @@ export interface DotenvParseOutput {
[name: string]: string;
}
export interface DotenvPopulateOutput {
[name: string]: string;
}
/**
* Parses a string or buffer in the .env file format into an object.
*
@ -144,10 +148,14 @@ export function configDotenv(options?: DotenvConfigOptions): DotenvConfigOutput;
* @param processEnv - the target JSON object. in most cases use process.env but you can also pass your own JSON object
* @param parsed - the source JSON object
* @param options - additional options. example: `{ quiet: false, debug: true, override: false }`
* @returns {void}
* @returns an object with the keys and values that were actually set
*
*/
export function populate(processEnv: DotenvPopulateInput, parsed: DotenvPopulateInput, options?: DotenvConfigOptions): void;
export function populate(
processEnv: DotenvPopulateInput,
parsed: DotenvPopulateInput,
options?: DotenvConfigOptions
): DotenvPopulateOutput;
/**
* Decrypt ciphertext

View file

@ -6,6 +6,43 @@ const packageJson = require('../package.json')
const version = packageJson.version
// Array of tips to display randomly
const TIPS = [
'🔐 encrypt with Dotenvx: https://dotenvx.com',
'🔐 prevent committing .env to code: https://dotenvx.com/precommit',
'🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
'📡 observe env with Radar: https://dotenvx.com/radar',
'📡 auto-backup env with Radar: https://dotenvx.com/radar',
'📡 version env with Radar: https://dotenvx.com/radar',
'🛠️ run anywhere with `dotenvx run -- yourcommand`',
'⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
'⚙️ enable debug logging with { debug: true }',
'⚙️ override existing env vars with { override: true }',
'⚙️ suppress all logs with { quiet: true }',
'⚙️ write to custom object with { processEnv: myObject }',
'⚙️ load multiple .env files with { path: [\'.env.local\', \'.env\'] }'
]
// Get a random tip from the tips array
function _getRandomTip () {
return TIPS[Math.floor(Math.random() * TIPS.length)]
}
function parseBoolean (value) {
if (typeof value === 'string') {
return !['false', '0', 'no', 'off', ''].includes(value.toLowerCase())
}
return Boolean(value)
}
function supportsAnsi () {
return process.stdout.isTTY // && process.env.TERM !== 'dumb'
}
function dim (text) {
return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text
}
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
// Parse src into an Object
@ -189,8 +226,8 @@ function _resolveHome (envPath) {
}
function _configVault (options) {
const debug = Boolean(options && options.debug)
const quiet = Boolean(options && options.quiet)
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || (options && options.debug))
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || (options && options.quiet))
if (debug || !quiet) {
_log('Loading env from encrypted .env.vault')
@ -211,8 +248,12 @@ function _configVault (options) {
function configDotenv (options) {
const dotenvPath = path.resolve(process.cwd(), '.env')
let encoding = 'utf8'
const debug = Boolean(options && options.debug)
const quiet = Boolean(options && options.quiet)
let processEnv = process.env
if (options && options.processEnv != null) {
processEnv = options.processEnv
}
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || (options && options.debug))
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || (options && options.quiet))
if (options && options.encoding) {
encoding = options.encoding
@ -252,15 +293,14 @@ function configDotenv (options) {
}
}
let processEnv = process.env
if (options && options.processEnv != null) {
processEnv = options.processEnv
}
const populated = DotenvModule.populate(processEnv, parsedAll, options)
DotenvModule.populate(processEnv, parsedAll, options)
// handle user settings DOTENV_CONFIG_ options inside .env file(s)
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug)
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet)
if (debug || !quiet) {
const keysCount = Object.keys(parsedAll).length
const keysCount = Object.keys(populated).length
const shortPaths = []
for (const filePath of optionPaths) {
try {
@ -274,7 +314,7 @@ function configDotenv (options) {
}
}
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} – 🔐 encrypt with dotenvx: https://dotenvx.com`)
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`-- tip: ${_getRandomTip()}`)}`)
}
if (lastError) {
@ -338,6 +378,7 @@ function decrypt (encrypted, keyStr) {
function populate (processEnv, parsed, options = {}) {
const debug = Boolean(options && options.debug)
const override = Boolean(options && options.override)
const populated = {}
if (typeof parsed !== 'object') {
const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
@ -350,6 +391,7 @@ function populate (processEnv, parsed, options = {}) {
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
if (override === true) {
processEnv[key] = parsed[key]
populated[key] = parsed[key]
}
if (debug) {
@ -361,8 +403,11 @@ function populate (processEnv, parsed, options = {}) {
}
} else {
processEnv[key] = parsed[key]
populated[key] = parsed[key]
}
}
return populated
}
const DotenvModule = {

View file

@ -1,6 +1,6 @@
{
"name": "dotenv",
"version": "17.0.0",
"version": "17.2.1",
"description": "Loads environment variables from .env file",
"main": "lib/main.js",
"types": "lib/main.d.ts",

601
Backend/node_modules/form-data/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,601 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v4.0.4](https://github.com/form-data/form-data/compare/v4.0.3...v4.0.4) - 2025-07-16
### Commits
- [meta] add `auto-changelog` [`811f682`](https://github.com/form-data/form-data/commit/811f68282fab0315209d0e2d1c44b6c32ea0d479)
- [Tests] handle predict-v8-randomness failures in node &lt; 17 and node &gt; 23 [`1d11a76`](https://github.com/form-data/form-data/commit/1d11a76434d101f22fdb26b8aef8615f28b98402)
- [Fix] Switch to using `crypto` random for boundary values [`3d17230`](https://github.com/form-data/form-data/commit/3d1723080e6577a66f17f163ecd345a21d8d0fd0)
- [Tests] fix linting errors [`5e34080`](https://github.com/form-data/form-data/commit/5e340800b5f8914213e4e0378c084aae71cfd73a)
- [meta] actually ensure the readme backup isn’t published [`316c82b`](https://github.com/form-data/form-data/commit/316c82ba93fd4985af757b771b9a1f26d3b709ef)
- [Dev Deps] update `@ljharb/eslint-config` [`58c25d7`](https://github.com/form-data/form-data/commit/58c25d76406a5b0dfdf54045cf252563f2bbda8d)
- [meta] fix readme capitalization [`2300ca1`](https://github.com/form-data/form-data/commit/2300ca19595b0ee96431e868fe2a40db79e41c61)
## [v4.0.3](https://github.com/form-data/form-data/compare/v4.0.2...v4.0.3) - 2025-06-05
### Fixed
- [Fix] `append`: avoid a crash on nullish values [`#577`](https://github.com/form-data/form-data/issues/577)
### Commits
- [eslint] use a shared config [`426ba9a`](https://github.com/form-data/form-data/commit/426ba9ac440f95d1998dac9a5cd8d738043b048f)
- [eslint] fix some spacing issues [`2094191`](https://github.com/form-data/form-data/commit/20941917f0e9487e68c564ebc3157e23609e2939)
- [Refactor] use `hasown` [`81ab41b`](https://github.com/form-data/form-data/commit/81ab41b46fdf34f5d89d7ff30b513b0925febfaa)
- [Fix] validate boundary type in `setBoundary()` method [`8d8e469`](https://github.com/form-data/form-data/commit/8d8e4693093519f7f18e3c597d1e8df8c493de9e)
- [Tests] add tests to check the behavior of `getBoundary` with non-strings [`837b8a1`](https://github.com/form-data/form-data/commit/837b8a1f7562bfb8bda74f3fc538adb7a5858995)
- [Dev Deps] remove unused deps [`870e4e6`](https://github.com/form-data/form-data/commit/870e4e665935e701bf983a051244ab928e62d58e)
- [meta] remove local commit hooks [`e6e83cc`](https://github.com/form-data/form-data/commit/e6e83ccb545a5619ed6cd04f31d5c2f655eb633e)
- [Dev Deps] update `eslint` [`4066fd6`](https://github.com/form-data/form-data/commit/4066fd6f65992b62fa324a6474a9292a4f88c916)
- [meta] fix scripts to use prepublishOnly [`c4bbb13`](https://github.com/form-data/form-data/commit/c4bbb13c0ef669916657bc129341301b1d331d75)
## [v4.0.2](https://github.com/form-data/form-data/compare/v4.0.1...v4.0.2) - 2025-02-14
### Merged
- [Fix] set `Symbol.toStringTag` when available [`#573`](https://github.com/form-data/form-data/pull/573)
- [Fix] set `Symbol.toStringTag` when available [`#573`](https://github.com/form-data/form-data/pull/573)
- fix (npmignore): ignore temporary build files [`#532`](https://github.com/form-data/form-data/pull/532)
- fix (npmignore): ignore temporary build files [`#532`](https://github.com/form-data/form-data/pull/532)
### Fixed
- [Fix] set `Symbol.toStringTag` when available (#573) [`#396`](https://github.com/form-data/form-data/issues/396)
- [Fix] set `Symbol.toStringTag` when available (#573) [`#396`](https://github.com/form-data/form-data/issues/396)
- [Fix] set `Symbol.toStringTag` when available [`#396`](https://github.com/form-data/form-data/issues/396)
### Commits
- Merge tags v2.5.3 and v3.0.3 [`92613b9`](https://github.com/form-data/form-data/commit/92613b9208556eb4ebc482fdf599fae111626fb6)
- [Tests] migrate from travis to GHA [`806eda7`](https://github.com/form-data/form-data/commit/806eda77740e6e3c67c7815afb216f2e1f187ba5)
- [Tests] migrate from travis to GHA [`8fdb3bc`](https://github.com/form-data/form-data/commit/8fdb3bc6b5d001f8909a9fca391d1d1d97ef1d79)
- [Refactor] use `Object.prototype.hasOwnProperty.call` [`7fecefe`](https://github.com/form-data/form-data/commit/7fecefe4ba8f775634aff86a698776ad95ecffb5)
- [Refactor] use `Object.prototype.hasOwnProperty.call` [`6e682d4`](https://github.com/form-data/form-data/commit/6e682d4bd41de7e80de41e3c4ee10f23fcc3dd00)
- [Refactor] use `Object.prototype.hasOwnProperty.call` [`df3c1e6`](https://github.com/form-data/form-data/commit/df3c1e6f0937f47a782dc4573756a54987f31dde)
- [Dev Deps] update `@types/node`, `browserify`, `coveralls`, `cross-spawn`, `eslint`, `formidable`, `in-publish`, `pkgfiles`, `pre-commit`, `puppeteer`, `request`, `tape`, `typescript` [`8261fcb`](https://github.com/form-data/form-data/commit/8261fcb8bf5944d30ae3bd04b91b71d6a9932ef4)
- [Dev Deps] update `@types/node`, `browserify`, `coveralls`, `cross-spawn`, `eslint`, `formidable`, `in-publish`, `pkgfiles`, `pre-commit`, `puppeteer`, `request`, `tape`, `typescript` [`fb66cb7`](https://github.com/form-data/form-data/commit/fb66cb740e29fb170eee947d4be6fdf82d6659af)
- [Dev Deps] update `@types/node`, `browserify`, `coveralls`, `eslint`, `formidable`, `in-publish`, `phantomjs-prebuilt`, `pkgfiles`, `pre-commit`, `request`, `tape`, `typescript` [`819f6b7`](https://github.com/form-data/form-data/commit/819f6b7a543306a891fca37c3a06d0ff4a734422)
- [eslint] clean up ignores [`3217b3d`](https://github.com/form-data/form-data/commit/3217b3ded8e382e51171d5c74c6038a21cc54440)
- [eslint] clean up ignores [`3a9d480`](https://github.com/form-data/form-data/commit/3a9d480232dbcbc07260ad84c3da4975d9a3ae9e)
- [Fix] `Buffer.from` and `Buffer.alloc` require node 4+ [`c499f76`](https://github.com/form-data/form-data/commit/c499f76f1faac1ddbf210c45217038e4c1e02337)
- Only apps should have lockfiles [`b82f590`](https://github.com/form-data/form-data/commit/b82f59093cdbadb4b7ec0922d33ae7ab048b82ff)
- Only apps should have lockfiles [`b170ee2`](https://github.com/form-data/form-data/commit/b170ee2b22b4c695c363b811c0c553d2fb1bbd79)
- [Deps] update `combined-stream`, `mime-types` [`6b1ca1d`](https://github.com/form-data/form-data/commit/6b1ca1dc7362a1b1c3a99a885516cca4b7eb817f)
- [Dev Deps] pin `request` which via `tough-cookie` ^2.4 depends on `psl` [`e5df7f2`](https://github.com/form-data/form-data/commit/e5df7f24383342264bd73dee3274818a40d04065)
- [Deps] update `mime-types` [`5a5bafe`](https://github.com/form-data/form-data/commit/5a5bafee894fead10da49e1fa2b084e17f2e1034)
- Bumped version 2.5.3 [`9457283`](https://github.com/form-data/form-data/commit/9457283e1dce6122adc908fdd7442cfc54cabe7a)
- [Dev Deps] pin `request` which via `tough-cookie` ^2.4 depends on `psl` [`9dbe192`](https://github.com/form-data/form-data/commit/9dbe192be3db215eac4d9c0b980470a5c2c030c6)
- Merge tags v2.5.2 and v3.0.2 [`d53265d`](https://github.com/form-data/form-data/commit/d53265d86c5153f535ec68eb107548b1b2883576)
- Bumped version 2.5.2 [`7020dd4`](https://github.com/form-data/form-data/commit/7020dd4c1260370abc40e86e3dfe49c5d576fbda)
- [Dev Deps] downgrade `cross-spawn` [`3fc1a9b`](https://github.com/form-data/form-data/commit/3fc1a9b62ddf1fe77a2bd6bd3476e4c0a9e01a88)
- fix: move util.isArray to Array.isArray (#564) [`edb555a`](https://github.com/form-data/form-data/commit/edb555a811f6f7e4668db4831551cf41c1de1cac)
- fix: move util.isArray to Array.isArray (#564) [`10418d1`](https://github.com/form-data/form-data/commit/10418d1fe4b0d65fe020eafe3911feb5ad5e2bd6)
## [v4.0.1](https://github.com/form-data/form-data/compare/v4.0.0...v4.0.1) - 2024-10-10
### Commits
- [Tests] migrate from travis to GHA [`757b4e3`](https://github.com/form-data/form-data/commit/757b4e32e95726aec9bdcc771fb5a3b564d88034)
- [eslint] clean up ignores [`e8f0d80`](https://github.com/form-data/form-data/commit/e8f0d80cd7cd424d1488532621ec40a33218b30b)
- fix (npmignore): ignore temporary build files [`335ad19`](https://github.com/form-data/form-data/commit/335ad19c6e17dc2d7298ffe0e9b37ba63600e94b)
- fix: move util.isArray to Array.isArray [`440d3be`](https://github.com/form-data/form-data/commit/440d3bed752ac2f9213b4c2229dbccefe140e5fa)
## [v4.0.0](https://github.com/form-data/form-data/compare/v3.0.3...v4.0.0) - 2021-02-15
### Merged
- Handle custom stream [`#382`](https://github.com/form-data/form-data/pull/382)
### Commits
- Fix typo [`e705c0a`](https://github.com/form-data/form-data/commit/e705c0a1fdaf90d21501f56460b93e43a18bd435)
- Update README for custom stream behavior [`6dd8624`](https://github.com/form-data/form-data/commit/6dd8624b2999e32768d62752c9aae5845a803b0d)
## [v3.0.3](https://github.com/form-data/form-data/compare/v3.0.2...v3.0.3) - 2025-02-14
### Merged
- [Fix] set `Symbol.toStringTag` when available [`#573`](https://github.com/form-data/form-data/pull/573)
### Fixed
- [Fix] set `Symbol.toStringTag` when available (#573) [`#396`](https://github.com/form-data/form-data/issues/396)
### Commits
- [Refactor] use `Object.prototype.hasOwnProperty.call` [`7fecefe`](https://github.com/form-data/form-data/commit/7fecefe4ba8f775634aff86a698776ad95ecffb5)
- [Dev Deps] update `@types/node`, `browserify`, `coveralls`, `cross-spawn`, `eslint`, `formidable`, `in-publish`, `pkgfiles`, `pre-commit`, `puppeteer`, `request`, `tape`, `typescript` [`8261fcb`](https://github.com/form-data/form-data/commit/8261fcb8bf5944d30ae3bd04b91b71d6a9932ef4)
- Only apps should have lockfiles [`b82f590`](https://github.com/form-data/form-data/commit/b82f59093cdbadb4b7ec0922d33ae7ab048b82ff)
- [Dev Deps] pin `request` which via `tough-cookie` ^2.4 depends on `psl` [`e5df7f2`](https://github.com/form-data/form-data/commit/e5df7f24383342264bd73dee3274818a40d04065)
- [Deps] update `mime-types` [`5a5bafe`](https://github.com/form-data/form-data/commit/5a5bafee894fead10da49e1fa2b084e17f2e1034)
## [v3.0.2](https://github.com/form-data/form-data/compare/v3.0.1...v3.0.2) - 2024-10-10
### Merged
- fix (npmignore): ignore temporary build files [`#532`](https://github.com/form-data/form-data/pull/532)
### Commits
- [Tests] migrate from travis to GHA [`8fdb3bc`](https://github.com/form-data/form-data/commit/8fdb3bc6b5d001f8909a9fca391d1d1d97ef1d79)
- [eslint] clean up ignores [`3217b3d`](https://github.com/form-data/form-data/commit/3217b3ded8e382e51171d5c74c6038a21cc54440)
- fix: move util.isArray to Array.isArray (#564) [`edb555a`](https://github.com/form-data/form-data/commit/edb555a811f6f7e4668db4831551cf41c1de1cac)
## [v3.0.1](https://github.com/form-data/form-data/compare/v3.0.0...v3.0.1) - 2021-02-15
### Merged
- Fix typo: ads -&gt; adds [`#451`](https://github.com/form-data/form-data/pull/451)
### Commits
- feat: add setBoundary method [`55d90ce`](https://github.com/form-data/form-data/commit/55d90ce4a4c22b0ea0647991d85cb946dfb7395b)
## [v3.0.0](https://github.com/form-data/form-data/compare/v2.5.3...v3.0.0) - 2019-11-05
### Merged
- Update Readme.md [`#449`](https://github.com/form-data/form-data/pull/449)
- Update package.json [`#448`](https://github.com/form-data/form-data/pull/448)
- fix memory leak [`#447`](https://github.com/form-data/form-data/pull/447)
- form-data: Replaced PhantomJS Dependency [`#442`](https://github.com/form-data/form-data/pull/442)
- Fix constructor options in Typescript definitions [`#446`](https://github.com/form-data/form-data/pull/446)
- Fix the getHeaders method signatures [`#434`](https://github.com/form-data/form-data/pull/434)
- Update combined-stream (fixes #422) [`#424`](https://github.com/form-data/form-data/pull/424)
### Fixed
- Merge pull request #424 from botgram/update-combined-stream [`#422`](https://github.com/form-data/form-data/issues/422)
- Update combined-stream (fixes #422) [`#422`](https://github.com/form-data/form-data/issues/422)
### Commits
- Add readable stream options to constructor type [`80c8f74`](https://github.com/form-data/form-data/commit/80c8f746bcf4c0418ae35fbedde12fb8c01e2748)
- Fixed: getHeaders method signatures [`f4ca7f8`](https://github.com/form-data/form-data/commit/f4ca7f8e31f7e07df22c1aeb8e0a32a7055a64ca)
- Pass options to constructor if not used with new [`4bde68e`](https://github.com/form-data/form-data/commit/4bde68e12de1ba90fefad2e7e643f6375b902763)
- Make userHeaders optional [`2b4e478`](https://github.com/form-data/form-data/commit/2b4e4787031490942f2d1ee55c56b85a250875a7)
## [v2.5.3](https://github.com/form-data/form-data/compare/v2.5.2...v2.5.3) - 2025-02-14
### Merged
- [Fix] set `Symbol.toStringTag` when available [`#573`](https://github.com/form-data/form-data/pull/573)
### Fixed
- [Fix] set `Symbol.toStringTag` when available (#573) [`#396`](https://github.com/form-data/form-data/issues/396)
### Commits
- [Refactor] use `Object.prototype.hasOwnProperty.call` [`6e682d4`](https://github.com/form-data/form-data/commit/6e682d4bd41de7e80de41e3c4ee10f23fcc3dd00)
- [Dev Deps] update `@types/node`, `browserify`, `coveralls`, `eslint`, `formidable`, `in-publish`, `phantomjs-prebuilt`, `pkgfiles`, `pre-commit`, `request`, `tape`, `typescript` [`819f6b7`](https://github.com/form-data/form-data/commit/819f6b7a543306a891fca37c3a06d0ff4a734422)
- Only apps should have lockfiles [`b170ee2`](https://github.com/form-data/form-data/commit/b170ee2b22b4c695c363b811c0c553d2fb1bbd79)
- [Deps] update `combined-stream`, `mime-types` [`6b1ca1d`](https://github.com/form-data/form-data/commit/6b1ca1dc7362a1b1c3a99a885516cca4b7eb817f)
- Bumped version 2.5.3 [`9457283`](https://github.com/form-data/form-data/commit/9457283e1dce6122adc908fdd7442cfc54cabe7a)
- [Dev Deps] pin `request` which via `tough-cookie` ^2.4 depends on `psl` [`9dbe192`](https://github.com/form-data/form-data/commit/9dbe192be3db215eac4d9c0b980470a5c2c030c6)
## [v2.5.2](https://github.com/form-data/form-data/compare/v2.5.1...v2.5.2) - 2024-10-10
### Merged
- fix (npmignore): ignore temporary build files [`#532`](https://github.com/form-data/form-data/pull/532)
### Commits
- [Tests] migrate from travis to GHA [`806eda7`](https://github.com/form-data/form-data/commit/806eda77740e6e3c67c7815afb216f2e1f187ba5)
- [eslint] clean up ignores [`3a9d480`](https://github.com/form-data/form-data/commit/3a9d480232dbcbc07260ad84c3da4975d9a3ae9e)
- [Fix] `Buffer.from` and `Buffer.alloc` require node 4+ [`c499f76`](https://github.com/form-data/form-data/commit/c499f76f1faac1ddbf210c45217038e4c1e02337)
- Bumped version 2.5.2 [`7020dd4`](https://github.com/form-data/form-data/commit/7020dd4c1260370abc40e86e3dfe49c5d576fbda)
- [Dev Deps] downgrade `cross-spawn` [`3fc1a9b`](https://github.com/form-data/form-data/commit/3fc1a9b62ddf1fe77a2bd6bd3476e4c0a9e01a88)
- fix: move util.isArray to Array.isArray (#564) [`10418d1`](https://github.com/form-data/form-data/commit/10418d1fe4b0d65fe020eafe3911feb5ad5e2bd6)
## [v2.5.1](https://github.com/form-data/form-data/compare/v2.5.0...v2.5.1) - 2019-08-28
### Merged
- Fix error in callback signatures [`#435`](https://github.com/form-data/form-data/pull/435)
- -Fixed: Eerror in the documentations as indicated in #439 [`#440`](https://github.com/form-data/form-data/pull/440)
- Add constructor options to TypeScript defs [`#437`](https://github.com/form-data/form-data/pull/437)
### Commits
- Add remaining combined-stream options to typedef [`4d41a32`](https://github.com/form-data/form-data/commit/4d41a32c0b3f85f8bbc9cf17df43befd2d5fc305)
- Bumped version 2.5.1 [`8ce81f5`](https://github.com/form-data/form-data/commit/8ce81f56cccf5466363a5eff135ad394a929f59b)
- Bump rimraf to 2.7.1 [`a6bc2d4`](https://github.com/form-data/form-data/commit/a6bc2d4296dbdee5d84cbab7c69bcd0eea7a12e2)
## [v2.5.0](https://github.com/form-data/form-data/compare/v2.4.0...v2.5.0) - 2019-07-03
### Merged
- - Added: public methods with information and examples to readme [`#429`](https://github.com/form-data/form-data/pull/429)
- chore: move @types/node to devDep [`#431`](https://github.com/form-data/form-data/pull/431)
- Switched windows tests from AppVeyor to Travis [`#430`](https://github.com/form-data/form-data/pull/430)
- feat(typings): migrate TS typings #427 [`#428`](https://github.com/form-data/form-data/pull/428)
- enhance the method of path.basename, handle undefined case [`#421`](https://github.com/form-data/form-data/pull/421)
### Commits
- - Added: public methods with information and examples to the readme file. [`21323f3`](https://github.com/form-data/form-data/commit/21323f3b4043a167046a4a2554c5f2825356c423)
- feat(typings): migrate TS typings [`a3c0142`](https://github.com/form-data/form-data/commit/a3c0142ed91b0c7dcaf89c4f618776708f1f70a9)
- - Fixed: Typos [`37350fa`](https://github.com/form-data/form-data/commit/37350fa250782f156a998ec1fa9671866d40ac49)
- Switched to Travis Windows from Appveyor [`fc61c73`](https://github.com/form-data/form-data/commit/fc61c7381fad12662df16dbc3e7621c91b886f03)
- - Fixed: rendering of subheaders [`e93ed8d`](https://github.com/form-data/form-data/commit/e93ed8df9d7f22078bc3a2c24889e9dfa11e192d)
- Updated deps and readme [`e3d8628`](https://github.com/form-data/form-data/commit/e3d8628728f6e4817ab97deeed92f0c822661b89)
- Updated dependencies [`19add50`](https://github.com/form-data/form-data/commit/19add50afb7de66c70d189f422d16f1b886616e2)
- Bumped version to 2.5.0 [`905f173`](https://github.com/form-data/form-data/commit/905f173a3f785e8d312998e765634ee451ca5f42)
- - Fixed: filesize is not a valid option? knownLength should be used for streams [`d88f912`](https://github.com/form-data/form-data/commit/d88f912b75b666b47f8674467516eade69d2d5be)
- Bump notion of modern node to node8 [`508b626`](https://github.com/form-data/form-data/commit/508b626bf1b460d3733d3420dc1cfd001617f6ac)
- enhance the method of path.basename [`faaa68a`](https://github.com/form-data/form-data/commit/faaa68a297be7d4fca0ac4709d5b93afc1f78b5c)
## [v2.4.0](https://github.com/form-data/form-data/compare/v2.3.2...v2.4.0) - 2019-06-19
### Merged
- Added "getBuffer" method and updated certificates [`#419`](https://github.com/form-data/form-data/pull/419)
- docs(readme): add axios integration document [`#425`](https://github.com/form-data/form-data/pull/425)
- Allow newer versions of combined-stream [`#402`](https://github.com/form-data/form-data/pull/402)
### Commits
- Updated: Certificate [`e90a76a`](https://github.com/form-data/form-data/commit/e90a76ab3dcaa63a6f3045f8255bfbb9c25a3e4e)
- Updated build/test/badges [`8512eef`](https://github.com/form-data/form-data/commit/8512eef436e28372f5bc88de3ca76a9cb46e6847)
- Bumped version 2.4.0 [`0f8da06`](https://github.com/form-data/form-data/commit/0f8da06c0b4c997bd2f6b09d78290d339616a950)
- docs(readme): remove unnecessary bracket [`4e3954d`](https://github.com/form-data/form-data/commit/4e3954dde304d27e3b95371d8c78002f3af5d5b2)
- Bumped version to 2.3.3 [`b16916a`](https://github.com/form-data/form-data/commit/b16916a568a0d06f3f8a16c31f9a8b89b7844094)
## [v2.3.2](https://github.com/form-data/form-data/compare/v2.3.1...v2.3.2) - 2018-02-13
### Merged
- Pulling in fixed combined-stream [`#379`](https://github.com/form-data/form-data/pull/379)
### Commits
- All the dev dependencies are breaking in old versions of node :'( [`c7dba6a`](https://github.com/form-data/form-data/commit/c7dba6a139d872d173454845e25e1850ed6b72b4)
- Updated badges [`19b6c7a`](https://github.com/form-data/form-data/commit/19b6c7a8a5c40f47f91c8a8da3e5e4dc3c449fa3)
- Try tests in node@4 [`872a326`](https://github.com/form-data/form-data/commit/872a326ab13e2740b660ff589b75232c3a85fcc9)
- Pull in final version [`9d44871`](https://github.com/form-data/form-data/commit/9d44871073d647995270b19dbc26f65671ce15c7)
## [v2.3.1](https://github.com/form-data/form-data/compare/v2.3.0...v2.3.1) - 2017-08-24
### Commits
- Updated readme with custom options example [`8e0a569`](https://github.com/form-data/form-data/commit/8e0a5697026016fe171e93bec43c2205279e23ca)
- Added support (tests) for node 8 [`d1d6f4a`](https://github.com/form-data/form-data/commit/d1d6f4ad4670d8ba84cc85b28e522ca0e93eb362)
## [v2.3.0](https://github.com/form-data/form-data/compare/v2.2.0...v2.3.0) - 2017-08-24
### Merged
- Added custom `options` support [`#368`](https://github.com/form-data/form-data/pull/368)
- Allow form.submit with url string param to use https [`#249`](https://github.com/form-data/form-data/pull/249)
- Proper header production [`#357`](https://github.com/form-data/form-data/pull/357)
- Fix wrong MIME type in example [`#285`](https://github.com/form-data/form-data/pull/285)
### Commits
- allow form.submit with url string param to use https [`c0390dc`](https://github.com/form-data/form-data/commit/c0390dcc623e15215308fa2bb0225aa431d9381e)
- update tests for url parsing [`eec0e80`](https://github.com/form-data/form-data/commit/eec0e807889d46697abd39a89ad9bf39996ba787)
- Uses for in to assign properties instead of Object.assign [`f6854ed`](https://github.com/form-data/form-data/commit/f6854edd85c708191bb9c89615a09fd0a9afe518)
- Adds test to check for option override [`61762f2`](https://github.com/form-data/form-data/commit/61762f2c5262e576d6a7f778b4ebab6546ef8582)
- Removes the 2mb maxDataSize limitation [`dc171c3`](https://github.com/form-data/form-data/commit/dc171c3ba49ac9b8813636fd4159d139b812315b)
- Ignore .DS_Store [`e8a05d3`](https://github.com/form-data/form-data/commit/e8a05d33361f7dca8927fe1d96433d049843de24)
## [v2.2.0](https://github.com/form-data/form-data/compare/v2.1.4...v2.2.0) - 2017-06-11
### Merged
- Filename can be a nested path [`#355`](https://github.com/form-data/form-data/pull/355)
### Commits
- Bumped version number. [`d7398c3`](https://github.com/form-data/form-data/commit/d7398c3e7cd81ed12ecc0b84363721bae467db02)
## [v2.1.4](https://github.com/form-data/form-data/compare/2.1.3...v2.1.4) - 2017-04-08
## [2.1.3](https://github.com/form-data/form-data/compare/v2.1.3...2.1.3) - 2017-04-08
## [v2.1.3](https://github.com/form-data/form-data/compare/v2.1.2...v2.1.3) - 2017-04-08
### Merged
- toString should output '[object FormData]' [`#346`](https://github.com/form-data/form-data/pull/346)
## [v2.1.2](https://github.com/form-data/form-data/compare/v2.1.1...v2.1.2) - 2016-11-07
### Merged
- #271 Added check for self and window objects + tests [`#282`](https://github.com/form-data/form-data/pull/282)
### Commits
- Added check for self and window objects + tests [`c99e4ec`](https://github.com/form-data/form-data/commit/c99e4ec32cd14d83776f2bdcc5a4e7384131c1b1)
## [v2.1.1](https://github.com/form-data/form-data/compare/v2.1.0...v2.1.1) - 2016-10-03
### Merged
- Bumped dependencies. [`#270`](https://github.com/form-data/form-data/pull/270)
- Update browser.js shim to use self instead of window [`#267`](https://github.com/form-data/form-data/pull/267)
- Boilerplate code rediction [`#265`](https://github.com/form-data/form-data/pull/265)
- eslint@3.7.0 [`#266`](https://github.com/form-data/form-data/pull/266)
### Commits
- code duplicates removed [`e9239fb`](https://github.com/form-data/form-data/commit/e9239fbe7d3c897b29fe3bde857d772469541c01)
- Changed according to requests [`aa99246`](https://github.com/form-data/form-data/commit/aa9924626bd9168334d73fea568c0ad9d8fbaa96)
- chore(package): update eslint to version 3.7.0 [`090a859`](https://github.com/form-data/form-data/commit/090a859835016cab0de49629140499e418db9c3a)
## [v2.1.0](https://github.com/form-data/form-data/compare/v2.0.0...v2.1.0) - 2016-09-25
### Merged
- Added `hasKnownLength` public method [`#263`](https://github.com/form-data/form-data/pull/263)
### Commits
- Added hasKnownLength public method [`655b959`](https://github.com/form-data/form-data/commit/655b95988ef2ed3399f8796b29b2a8673c1df11c)
## [v2.0.0](https://github.com/form-data/form-data/compare/v1.0.0...v2.0.0) - 2016-09-16
### Merged
- Replaced async with asynckit [`#258`](https://github.com/form-data/form-data/pull/258)
- Pre-release house cleaning [`#247`](https://github.com/form-data/form-data/pull/247)
### Commits
- Replaced async with asynckit. Modernized [`1749b78`](https://github.com/form-data/form-data/commit/1749b78d50580fbd080e65c1eb9702ad4f4fc0c0)
- Ignore .bak files [`c08190a`](https://github.com/form-data/form-data/commit/c08190a87d3e22a528b6e32b622193742a4c2672)
- Trying to be more chatty. :) [`c79eabb`](https://github.com/form-data/form-data/commit/c79eabb24eaf761069255a44abf4f540cfd47d40)
## [v1.0.0](https://github.com/form-data/form-data/compare/v1.0.0-rc4...v1.0.0) - 2016-08-26
### Merged
- Allow custom header fields to be set as an object. [`#190`](https://github.com/form-data/form-data/pull/190)
- v1.0.0-rc4 [`#182`](https://github.com/form-data/form-data/pull/182)
- Avoid undefined variable reference in older browsers [`#176`](https://github.com/form-data/form-data/pull/176)
- More housecleaning [`#164`](https://github.com/form-data/form-data/pull/164)
- More cleanup [`#159`](https://github.com/form-data/form-data/pull/159)
- Added windows testing. Some cleanup. [`#158`](https://github.com/form-data/form-data/pull/158)
- Housecleaning. Added test coverage. [`#156`](https://github.com/form-data/form-data/pull/156)
- Second iteration of cleanup. [`#145`](https://github.com/form-data/form-data/pull/145)
### Commits
- Pre-release house cleaning [`440d72b`](https://github.com/form-data/form-data/commit/440d72b5fd44dd132f42598c3183d46e5f35ce71)
- Updated deps, updated docs [`54b6114`](https://github.com/form-data/form-data/commit/54b61143e9ce66a656dd537a1e7b31319a4991be)
- make docs up-to-date [`5e383d7`](https://github.com/form-data/form-data/commit/5e383d7f1466713f7fcef58a6817e0cb466c8ba7)
- Added missing deps [`fe04862`](https://github.com/form-data/form-data/commit/fe04862000b2762245e2db69d5207696a08c1174)
## [v1.0.0-rc4](https://github.com/form-data/form-data/compare/v1.0.0-rc3...v1.0.0-rc4) - 2016-03-15
### Merged
- Housecleaning, preparing for the release [`#144`](https://github.com/form-data/form-data/pull/144)
- lib: emit error when failing to get length [`#127`](https://github.com/form-data/form-data/pull/127)
- Cleaning up for Codacity 2. [`#143`](https://github.com/form-data/form-data/pull/143)
- Cleaned up codacity concerns. [`#142`](https://github.com/form-data/form-data/pull/142)
- Should throw type error without new operator. [`#129`](https://github.com/form-data/form-data/pull/129)
### Commits
- More cleanup [`94b6565`](https://github.com/form-data/form-data/commit/94b6565bb98a387335c72feff5ed5c10da0a7f6f)
- Shuffling things around [`3c2f172`](https://github.com/form-data/form-data/commit/3c2f172eaddf0979b3eef5c73985d1a6fd3eee4a)
- Second iteration of cleanup. [`347c88e`](https://github.com/form-data/form-data/commit/347c88ef9a99a66b9bcf4278497425db2f0182b2)
- Housecleaning [`c335610`](https://github.com/form-data/form-data/commit/c3356100c054a4695e4dec8ed7072775cd745616)
- More housecleaning [`f573321`](https://github.com/form-data/form-data/commit/f573321824aae37ba2052a92cc889d533d9f8fb8)
- Trying to make far run on windows. + cleanup [`e426dfc`](https://github.com/form-data/form-data/commit/e426dfcefb07ee307d8a15dec04044cce62413e6)
- Playing with appveyor [`c9458a7`](https://github.com/form-data/form-data/commit/c9458a7c328782b19859bc1745e7d6b2005ede86)
- Updated dev dependencies. [`ceebe88`](https://github.com/form-data/form-data/commit/ceebe88872bb22da0a5a98daf384e3cc232928d3)
- Replaced win-spawn with cross-spawn [`405a69e`](https://github.com/form-data/form-data/commit/405a69ee34e235ee6561b5ff0140b561be40d1cc)
- Updated readme badges. [`12f282a`](https://github.com/form-data/form-data/commit/12f282a1310fcc2f70cc5669782283929c32a63d)
- Making paths windows friendly. [`f4bddc5`](https://github.com/form-data/form-data/commit/f4bddc5955e2472f8e23c892c9b4d7a08fcb85a3)
- [WIP] trying things for greater sanity [`8ad1f02`](https://github.com/form-data/form-data/commit/8ad1f02b0b3db4a0b00c5d6145ed69bcb7558213)
- Bending under Codacy [`bfff3bb`](https://github.com/form-data/form-data/commit/bfff3bb36052dc83f429949b4e6f9b146a49d996)
- Another attempt to make windows friendly [`f3eb628`](https://github.com/form-data/form-data/commit/f3eb628974ccb91ba0020f41df490207eeed77f6)
- Updated dependencies. [`f73996e`](https://github.com/form-data/form-data/commit/f73996e0508ee2d4b2b376276adfac1de4188ac2)
- Missed travis changes. [`67ee79f`](https://github.com/form-data/form-data/commit/67ee79f964fdabaf300bd41b0af0c1cfaca07687)
- Restructured badges. [`48444a1`](https://github.com/form-data/form-data/commit/48444a1ff156ba2c2c3cfd11047c2f2fd92d4474)
- Add similar type error as the browser for attempting to use form-data without new. [`5711320`](https://github.com/form-data/form-data/commit/5711320fb7c8cc620cfc79b24c7721526e23e539)
- Took out codeclimate-test-reporter [`a7e0c65`](https://github.com/form-data/form-data/commit/a7e0c6522afe85ca9974b0b4e1fca9c77c3e52b1)
- One more [`8e84cff`](https://github.com/form-data/form-data/commit/8e84cff3370526ecd3e175fd98e966242d81993c)
## [v1.0.0-rc3](https://github.com/form-data/form-data/compare/v1.0.0-rc2...v1.0.0-rc3) - 2015-07-29
### Merged
- House cleaning. Added `pre-commit`. [`#140`](https://github.com/form-data/form-data/pull/140)
- Allow custom content-type without setting a filename. [`#138`](https://github.com/form-data/form-data/pull/138)
- Add node-fetch to alternative submission methods. [`#132`](https://github.com/form-data/form-data/pull/132)
- Update dependencies [`#130`](https://github.com/form-data/form-data/pull/130)
- Switching to container based TravisCI [`#136`](https://github.com/form-data/form-data/pull/136)
- Default content-type to 'application/octect-stream' [`#128`](https://github.com/form-data/form-data/pull/128)
- Allow filename as third option of .append [`#125`](https://github.com/form-data/form-data/pull/125)
### Commits
- Allow custom content-type without setting a filename [`c8a77cc`](https://github.com/form-data/form-data/commit/c8a77cc0cf16d15f1ebf25272beaab639ce89f76)
- Fixed ranged test. [`a5ac58c`](https://github.com/form-data/form-data/commit/a5ac58cbafd0909f32fe8301998f689314fd4859)
- Allow filename as third option of #append [`d081005`](https://github.com/form-data/form-data/commit/d0810058c84764b3c463a18b15ebb37864de9260)
- Allow custom content-type without setting a filename [`8cb9709`](https://github.com/form-data/form-data/commit/8cb9709e5f1809cfde0cd707dbabf277138cd771)
## [v1.0.0-rc2](https://github.com/form-data/form-data/compare/v1.0.0-rc1...v1.0.0-rc2) - 2015-07-21
### Merged
- #109 Append proper line break [`#123`](https://github.com/form-data/form-data/pull/123)
- Add shim for browser (browserify/webpack). [`#122`](https://github.com/form-data/form-data/pull/122)
- Update license field [`#115`](https://github.com/form-data/form-data/pull/115)
### Commits
- Add shim for browser. [`87c33f4`](https://github.com/form-data/form-data/commit/87c33f4269a2211938f80ab3e53835362b1afee8)
- Bump version [`a3f5d88`](https://github.com/form-data/form-data/commit/a3f5d8872c810ce240c7d3838c69c3c9fcecc111)
## [v1.0.0-rc1](https://github.com/form-data/form-data/compare/0.2...v1.0.0-rc1) - 2015-06-13
### Merged
- v1.0.0-rc1 [`#114`](https://github.com/form-data/form-data/pull/114)
- Updated test targets [`#102`](https://github.com/form-data/form-data/pull/102)
- Remove duplicate plus sign [`#94`](https://github.com/form-data/form-data/pull/94)
### Commits
- Made https test local. Updated deps. [`afe1959`](https://github.com/form-data/form-data/commit/afe1959ec711f23e57038ab5cb20fedd86271f29)
- Proper self-signed ssl [`4d5ec50`](https://github.com/form-data/form-data/commit/4d5ec50e81109ad2addf3dbb56dc7c134df5ff87)
- Update HTTPS handling for modern days [`2c11b01`](https://github.com/form-data/form-data/commit/2c11b01ce2c06e205c84d7154fa2f27b66c94f3b)
- Made tests more local [`09633fa`](https://github.com/form-data/form-data/commit/09633fa249e7ce3ac581543aafe16ee9039a823b)
- Auto create tmp folder for Formidable [`28714b7`](https://github.com/form-data/form-data/commit/28714b7f71ad556064cdff88fabe6b92bd407ddd)
- remove duplicate plus sign [`36e09c6`](https://github.com/form-data/form-data/commit/36e09c695b0514d91a23f5cd64e6805404776fc7)
## [0.2](https://github.com/form-data/form-data/compare/0.1.4...0.2) - 2014-12-06
### Merged
- Bumped version [`#96`](https://github.com/form-data/form-data/pull/96)
- Replace mime library. [`#95`](https://github.com/form-data/form-data/pull/95)
- #71 Respect bytes range in a read stream. [`#73`](https://github.com/form-data/form-data/pull/73)
## [0.1.4](https://github.com/form-data/form-data/compare/0.1.3...0.1.4) - 2014-06-23
### Merged
- Updated version. [`#76`](https://github.com/form-data/form-data/pull/76)
- #71 Respect bytes range in a read stream. [`#75`](https://github.com/form-data/form-data/pull/75)
## [0.1.3](https://github.com/form-data/form-data/compare/0.1.2...0.1.3) - 2014-06-17
### Merged
- Updated versions. [`#69`](https://github.com/form-data/form-data/pull/69)
- Added custom headers support [`#60`](https://github.com/form-data/form-data/pull/60)
- Added test for Request. Small fixes. [`#56`](https://github.com/form-data/form-data/pull/56)
### Commits
- Added test for the custom header functionality [`bd50685`](https://github.com/form-data/form-data/commit/bd506855af62daf728ef1718cae88ed23bb732f3)
- Documented custom headers option [`77a024a`](https://github.com/form-data/form-data/commit/77a024a9375f93c246c35513d80f37d5e11d35ff)
- Removed 0.6 support. [`aee8dce`](https://github.com/form-data/form-data/commit/aee8dce604c595cfaacfc6efb12453d1691ac0d6)
## [0.1.2](https://github.com/form-data/form-data/compare/0.1.1...0.1.2) - 2013-10-02
### Merged
- Fixed default https port assignment, added tests. [`#52`](https://github.com/form-data/form-data/pull/52)
- #45 Added tests for multi-submit. Updated readme. [`#49`](https://github.com/form-data/form-data/pull/49)
- #47 return request from .submit() [`#48`](https://github.com/form-data/form-data/pull/48)
### Commits
- Bumped version. [`2b761b2`](https://github.com/form-data/form-data/commit/2b761b256ae607fc2121621f12c2e1042be26baf)
## [0.1.1](https://github.com/form-data/form-data/compare/0.1.0...0.1.1) - 2013-08-21
### Merged
- Added license type and reference to package.json [`#46`](https://github.com/form-data/form-data/pull/46)
### Commits
- #47 return request from .submit() [`1d61c2d`](https://github.com/form-data/form-data/commit/1d61c2da518bd5e136550faa3b5235bb540f1e06)
- #47 Updated readme. [`e3dae15`](https://github.com/form-data/form-data/commit/e3dae1526bd3c3b9d7aff6075abdaac12c3cc60f)
## [0.1.0](https://github.com/form-data/form-data/compare/0.0.10...0.1.0) - 2013-07-08
### Merged
- Update master to 0.1.0 [`#44`](https://github.com/form-data/form-data/pull/44)
- 0.1.0 - Added error handling. Streamlined edge cases behavior. [`#43`](https://github.com/form-data/form-data/pull/43)
- Pointed badges back to mothership. [`#39`](https://github.com/form-data/form-data/pull/39)
- Updated node-fake to support 0.11 tests. [`#37`](https://github.com/form-data/form-data/pull/37)
- Updated tests to play nice with 0.10 [`#36`](https://github.com/form-data/form-data/pull/36)
- #32 Added .npmignore [`#34`](https://github.com/form-data/form-data/pull/34)
- Spring cleaning [`#30`](https://github.com/form-data/form-data/pull/30)
### Commits
- Added error handling. Streamlined edge cases behavior. [`4da496e`](https://github.com/form-data/form-data/commit/4da496e577cb9bc0fd6c94cbf9333a0082ce353a)
- Made tests more deterministic. [`7fc009b`](https://github.com/form-data/form-data/commit/7fc009b8a2cc9232514a44b2808b9f89ce68f7d2)
- Fixed styling. [`d373b41`](https://github.com/form-data/form-data/commit/d373b417e779024bc3326073e176383cd08c0b18)
- #40 Updated Readme.md regarding getLengthSync() [`efb373f`](https://github.com/form-data/form-data/commit/efb373fd63814d977960e0299d23c92cd876cfef)
- Updated readme. [`527e3a6`](https://github.com/form-data/form-data/commit/527e3a63b032cb6f576f597ad7ff2ebcf8a0b9b4)
## [0.0.10](https://github.com/form-data/form-data/compare/0.0.9...0.0.10) - 2013-05-08
### Commits
- Updated tests to play nice with 0.10. [`932b39b`](https://github.com/form-data/form-data/commit/932b39b773e49edcb2c5d2e58fe389ab6c42f47c)
- Added dependency tracking. [`3131d7f`](https://github.com/form-data/form-data/commit/3131d7f6996cd519d50547e4de1587fd80d0fa07)
## 0.0.9 - 2013-04-29
### Merged
- Custom params for form.submit() should cover most edge cases. [`#22`](https://github.com/form-data/form-data/pull/22)
- Updated Readme and version number. [`#20`](https://github.com/form-data/form-data/pull/20)
- Allow custom headers and pre-known length in parts [`#17`](https://github.com/form-data/form-data/pull/17)
- Bumped version number. [`#12`](https://github.com/form-data/form-data/pull/12)
- Fix for #10 [`#11`](https://github.com/form-data/form-data/pull/11)
- Bumped version number. [`#8`](https://github.com/form-data/form-data/pull/8)
- Added support for https destination, http-response and mikeal's request streams. [`#7`](https://github.com/form-data/form-data/pull/7)
- Updated git url. [`#6`](https://github.com/form-data/form-data/pull/6)
- Version bump. [`#5`](https://github.com/form-data/form-data/pull/5)
- Changes to support custom content-type and getLengthSync. [`#4`](https://github.com/form-data/form-data/pull/4)
- make .submit(url) use host from url, not 'localhost' [`#2`](https://github.com/form-data/form-data/pull/2)
- Make package.json JSON [`#1`](https://github.com/form-data/form-data/pull/1)
### Fixed
- Add MIT license [`#14`](https://github.com/form-data/form-data/issues/14)
### Commits
- Spring cleaning. [`850ba1b`](https://github.com/form-data/form-data/commit/850ba1b649b6856b0fa87bbcb04bc70ece0137a6)
- Added custom request params to form.submit(). Made tests more stable. [`de3502f`](https://github.com/form-data/form-data/commit/de3502f6c4a509f6ed12a7dd9dc2ce9c2e0a8d23)
- Basic form (no files) working [`6ffdc34`](https://github.com/form-data/form-data/commit/6ffdc343e8594cfc2efe1e27653ea39d8980a14e)
- Got initial test to pass [`9a59d08`](https://github.com/form-data/form-data/commit/9a59d08c024479fd3c9d99ba2f0893a47b3980f0)
- Implement initial getLength [`9060c91`](https://github.com/form-data/form-data/commit/9060c91b861a6573b73beddd11e866db422b5830)
- Make getLength work with file streams [`6f6b1e9`](https://github.com/form-data/form-data/commit/6f6b1e9b65951e6314167db33b446351702f5558)
- Implemented a simplistic submit() function [`41e9cc1`](https://github.com/form-data/form-data/commit/41e9cc124124721e53bc1d1459d45db1410c44e6)
- added test for custom headers and content-length in parts (felixge/node-form-data/17) [`b16d14e`](https://github.com/form-data/form-data/commit/b16d14e693670f5d52babec32cdedd1aa07c1aa4)
- Fixed code styling. [`5847424`](https://github.com/form-data/form-data/commit/5847424c666970fc2060acd619e8a78678888a82)
- #29 Added custom filename and content-type options to support identity-less streams. [`adf8b4a`](https://github.com/form-data/form-data/commit/adf8b4a41530795682cd3e35ffaf26b30288ccda)
- Initial Readme and package.json [`8c744e5`](https://github.com/form-data/form-data/commit/8c744e58be4014bdf432e11b718ed87f03e217af)
- allow append() to completely override header and boundary [`3fb2ad4`](https://github.com/form-data/form-data/commit/3fb2ad491f66e4b4ff16130be25b462820b8c972)
- Syntax highlighting [`ab3a6a5`](https://github.com/form-data/form-data/commit/ab3a6a5ed1ab77a2943ce3befcb2bb3cd9ff0330)
- Updated Readme.md [`de8f441`](https://github.com/form-data/form-data/commit/de8f44122ca754cbfedc0d2748e84add5ff0b669)
- Added examples to Readme file. [`c406ac9`](https://github.com/form-data/form-data/commit/c406ac921d299cbc130464ed19338a9ef97cb650)
- pass options.knownLength to set length at beginning, w/o waiting for async size calculation [`e2ac039`](https://github.com/form-data/form-data/commit/e2ac0397ff7c37c3dca74fa9925b55f832e4fa0b)
- Updated dependencies and added test command. [`09bd7cd`](https://github.com/form-data/form-data/commit/09bd7cd86f1ad7a58df1b135eb6eef0d290894b4)
- Bumped version. Updated readme. [`4581140`](https://github.com/form-data/form-data/commit/4581140f322758c6fc92019d342c7d7d6c94af5c)
- Test runner [`1707ebb`](https://github.com/form-data/form-data/commit/1707ebbd180856e6ed44e80c46b02557e2425762)
- Added .npmignore, bumped version. [`2e033e0`](https://github.com/form-data/form-data/commit/2e033e0e4be7c1457be090cd9b2996f19d8fb665)
- FormData.prototype.append takes and passes along options (for header) [`b519203`](https://github.com/form-data/form-data/commit/b51920387ed4da7b4e106fc07b9459f26b5ae2f0)
- Make package.json JSON [`bf1b58d`](https://github.com/form-data/form-data/commit/bf1b58df794b10fda86ed013eb9237b1e5032085)
- Add dependencies to package.json [`7413d0b`](https://github.com/form-data/form-data/commit/7413d0b4cf5546312d47ea426db8180619083974)
- Add convenient submit() interface [`55855e4`](https://github.com/form-data/form-data/commit/55855e4bea14585d4a3faf9e7318a56696adbc7d)
- Fix content type [`08b6ae3`](https://github.com/form-data/form-data/commit/08b6ae337b23ef1ba457ead72c9b133047df213c)
- Combatting travis rvm calls. [`409adfd`](https://github.com/form-data/form-data/commit/409adfd100a3cf4968a632c05ba58d92d262d144)
- Fixed Issue #2 [`b3a5d66`](https://github.com/form-data/form-data/commit/b3a5d661739dcd6921b444b81d5cb3c32fab655d)
- Fix for #10. [`bab70b9`](https://github.com/form-data/form-data/commit/bab70b9e803e17287632762073d227d6c59989e0)
- Trying workarounds for formidable - 0.6 "love". [`25782a3`](https://github.com/form-data/form-data/commit/25782a3f183d9c30668ec2bca6247ed83f10611c)
- change whitespace to conform with felixge's style guide [`9fa34f4`](https://github.com/form-data/form-data/commit/9fa34f433bece85ef73086a874c6f0164ab7f1f6)
- Add async to deps [`b7d1a6b`](https://github.com/form-data/form-data/commit/b7d1a6b10ee74be831de24ed76843e5a6935f155)
- typo [`7860a9c`](https://github.com/form-data/form-data/commit/7860a9c8a582f0745ce0e4a0549f4bffc29c0b50)
- Bumped version. [`fa36c1b`](https://github.com/form-data/form-data/commit/fa36c1b4229c34b85d7efd41908429b6d1da3bfc)
- Updated .gitignore [`de567bd`](https://github.com/form-data/form-data/commit/de567bde620e53b8e9b0ed3506e79491525ec558)
- Don't rely on resume() being called by pipe [`1deae47`](https://github.com/form-data/form-data/commit/1deae47e042bcd170bd5dbe2b4a4fa5356bb8aa2)
- One more wrong content type [`28f166d`](https://github.com/form-data/form-data/commit/28f166d443e2eb77f2559324014670674b97e46e)
- Another typo [`b959b6a`](https://github.com/form-data/form-data/commit/b959b6a2be061cac17f8d329b89cea109f0f32be)
- Typo [`698fa0a`](https://github.com/form-data/form-data/commit/698fa0aa5dbf4eeb77377415acc202a6fbe3f4a2)
- Being simply dumb. [`b614db8`](https://github.com/form-data/form-data/commit/b614db85702061149fbd98418605106975e72ade)
- Fixed typo in the filename. [`30af6be`](https://github.com/form-data/form-data/commit/30af6be13fb0c9e92b32e935317680b9d7599928)

View file

@ -6,11 +6,11 @@ The API of this library is inspired by the [XMLHttpRequest-2 FormData Interface]
[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
[![Linux Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=linux:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![MacOS Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=macos:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![Windows Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=windows:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![Linux Build](https://img.shields.io/travis/form-data/form-data/v4.0.4.svg?label=linux:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![MacOS Build](https://img.shields.io/travis/form-data/form-data/v4.0.4.svg?label=macos:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![Windows Build](https://img.shields.io/travis/form-data/form-data/v4.0.4.svg?label=windows:6.x-12.x)](https://travis-ci.org/form-data/form-data)
[![Coverage Status](https://img.shields.io/coveralls/form-data/form-data/master.svg?label=code+coverage)](https://coveralls.io/github/form-data/form-data?branch=master)
[![Coverage Status](https://img.shields.io/coveralls/form-data/form-data/v4.0.4.svg?label=code+coverage)](https://coveralls.io/github/form-data/form-data?branch=master)
[![Dependency Status](https://img.shields.io/david/form-data/form-data.svg)](https://david-dm.org/form-data/form-data)
## Install
@ -205,7 +205,7 @@ form.append( 'my_string', 'my value' );
form.append('my_integer', 1);
form.append('my_boolean', true);
form.append('my_buffer', new Buffer(10));
form.append( 'my_array_as_json', JSON.stringify( ['bird','cute'] ) )
form.append('my_array_as_json', JSON.stringify(['bird', 'cute']));
```
You may provide a string for options, or an object.
@ -239,10 +239,7 @@ var form = new FormData();
form.append('my_buffer', Buffer.from([0x4a,0x42,0x20,0x52,0x6f,0x63,0x6b,0x73]));
form.append('my_file', fs.readFileSync('/foo/bar.jpg'));
axios.post( 'https://example.com/path/to/api',
form.getBuffer(),
form.getHeaders()
)
axios.post('https://example.com/path/to/api', form.getBuffer(), form.getHeaders());
```
**Note:** Because the output is of type Buffer, you can only append types that are accepted by Buffer: *string, Buffer, ArrayBuffer, Array, or Array-like Object*. A ReadStream for example will result in an error.

View file

@ -1,2 +1,4 @@
'use strict';
/* eslint-env browser */
module.exports = typeof self == 'object' ? self.FormData : window.FormData;
module.exports = typeof self === 'object' ? self.FormData : window.FormData;

View file

@ -1,3 +1,5 @@
'use strict';
var CombinedStream = require('combined-stream');
var util = require('util');
var path = require('path');
@ -6,24 +8,20 @@ var https = require('https');
var parseUrl = require('url').parse;
var fs = require('fs');
var Stream = require('stream').Stream;
var crypto = require('crypto');
var mime = require('mime-types');
var asynckit = require('asynckit');
var setToStringTag = require('es-set-tostringtag');
var hasOwn = require('hasown');
var populate = require('./populate.js');
// Public API
module.exports = FormData;
// make it a Stream
util.inherits(FormData, CombinedStream);
/**
* Create readable "multipart/form-data" streams.
* Can be used to submit forms
* and file uploads to other web applications.
*
* @constructor
* @param {Object} options - Properties to be added/overriden for FormData and CombinedStream
* @param {object} options - Properties to be added/overriden for FormData and CombinedStream
*/
function FormData(options) {
if (!(this instanceof FormData)) {
@ -36,35 +34,39 @@ function FormData(options) {
CombinedStream.call(this);
options = options || {};
for (var option in options) {
options = options || {}; // eslint-disable-line no-param-reassign
for (var option in options) { // eslint-disable-line no-restricted-syntax
this[option] = options[option];
}
}
// make it a Stream
util.inherits(FormData, CombinedStream);
FormData.LINE_BREAK = '\r\n';
FormData.DEFAULT_CONTENT_TYPE = 'application/octet-stream';
FormData.prototype.append = function (field, value, options) {
options = options || {};
options = options || {}; // eslint-disable-line no-param-reassign
// allow filename as single option
if (typeof options == 'string') {
options = {filename: options};
if (typeof options === 'string') {
options = { filename: options }; // eslint-disable-line no-param-reassign
}
var append = CombinedStream.prototype.append.bind(this);
// all that streamy business can't handle numbers
if (typeof value == 'number') {
value = '' + value;
if (typeof value === 'number' || value == null) {
value = String(value); // eslint-disable-line no-param-reassign
}
// https://github.com/felixge/node-form-data/issues/38
if (Array.isArray(value)) {
// Please convert your array into string
// the way web server expects it
/*
* Please convert your array into string
* the way web server expects it
*/
this._error(new Error('Arrays are not supported.'));
return;
}
@ -83,12 +85,14 @@ FormData.prototype.append = function(field, value, options) {
FormData.prototype._trackLength = function (header, value, options) {
var valueLength = 0;
// used w/ getLengthSync(), when length is known.
// e.g. for streaming directly from a remote server,
// w/ a known file a size, and not wanting to wait for
// incoming file to finish to get its size.
/*
* used w/ getLengthSync(), when length is known.
* e.g. for streaming directly from a remote server,
* w/ a known file a size, and not wanting to wait for
* incoming file to finish to get its size.
*/
if (options.knownLength != null) {
valueLength += +options.knownLength;
valueLength += Number(options.knownLength);
} else if (Buffer.isBuffer(value)) {
valueLength = value.length;
} else if (typeof value === 'string') {
@ -98,12 +102,10 @@ FormData.prototype._trackLength = function(header, value, options) {
this._valueLength += valueLength;
// @check why add CRLF? does this account for custom/multiple CRLFs?
this._overheadLength +=
Buffer.byteLength(header) +
FormData.LINE_BREAK.length;
this._overheadLength += Buffer.byteLength(header) + FormData.LINE_BREAK.length;
// empty or either doesn't have path or not an http response or not a stream
if (!value || ( !value.path && !(value.readable && Object.prototype.hasOwnProperty.call(value, 'httpVersion')) && !(value instanceof Stream))) {
if (!value || (!value.path && !(value.readable && hasOwn(value, 'httpVersion')) && !(value instanceof Stream))) {
return;
}
@ -114,8 +116,7 @@ FormData.prototype._trackLength = function(header, value, options) {
};
FormData.prototype._lengthRetriever = function (value, callback) {
if (Object.prototype.hasOwnProperty.call(value, 'fd')) {
if (hasOwn(value, 'fd')) {
// take read range into a account
// `end` = Infinity –> read file till the end
//
@ -124,54 +125,52 @@ FormData.prototype._lengthRetriever = function(value, callback) {
// Fix it when node fixes it.
// https://github.com/joyent/node/issues/7819
if (value.end != undefined && value.end != Infinity && value.start != undefined) {
// when end specified
// no need to calculate range
// inclusive, starts with 0
callback(null, value.end + 1 - (value.start ? value.start : 0));
callback(null, value.end + 1 - (value.start ? value.start : 0)); // eslint-disable-line callback-return
// not that fast snoopy
} else {
// still need to fetch file size from fs
fs.stat(value.path, function (err, stat) {
var fileSize;
if (err) {
callback(err);
return;
}
// update final size based on the range options
fileSize = stat.size - (value.start ? value.start : 0);
var fileSize = stat.size - (value.start ? value.start : 0);
callback(null, fileSize);
});
}
// or http response
} else if (Object.prototype.hasOwnProperty.call(value, 'httpVersion')) {
callback(null, +value.headers['content-length']);
} else if (hasOwn(value, 'httpVersion')) {
callback(null, Number(value.headers['content-length'])); // eslint-disable-line callback-return
// or request stream http://github.com/mikeal/request
} else if (Object.prototype.hasOwnProperty.call(value, 'httpModule')) {
} else if (hasOwn(value, 'httpModule')) {
// wait till response come back
value.on('response', function (response) {
value.pause();
callback(null, +response.headers['content-length']);
callback(null, Number(response.headers['content-length']));
});
value.resume();
// something else
} else {
callback('Unknown stream');
callback('Unknown stream'); // eslint-disable-line callback-return
}
};
FormData.prototype._multiPartHeader = function (field, value, options) {
// custom header specified (as string)?
// it becomes responsible for boundary
// (e.g. to handle extra CRLFs on .NET servers)
if (typeof options.header == 'string') {
/*
* custom header specified (as string)?
* it becomes responsible for boundary
* (e.g. to handle extra CRLFs on .NET servers)
*/
if (typeof options.header === 'string') {
return options.header;
}
@ -187,18 +186,18 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
};
// allow custom headers.
if (typeof options.header == 'object') {
if (typeof options.header === 'object') {
populate(headers, options.header);
}
var header;
for (var prop in headers) {
if (Object.prototype.hasOwnProperty.call(headers, prop)) {
for (var prop in headers) { // eslint-disable-line no-restricted-syntax
if (hasOwn(headers, prop)) {
header = headers[prop];
// skip nullish headers.
if (header == null) {
continue;
continue; // eslint-disable-line no-restricted-syntax, no-continue
}
// convert all headers to arrays.
@ -216,49 +215,45 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK;
};
FormData.prototype._getContentDisposition = function(value, options) {
var filename
, contentDisposition
;
FormData.prototype._getContentDisposition = function (value, options) { // eslint-disable-line consistent-return
var filename;
if (typeof options.filepath === 'string') {
// custom filepath for relative paths
filename = path.normalize(options.filepath).replace(/\\/g, '/');
} else if (options.filename || value.name || value.path) {
// custom filename take precedence
// formidable and the browser add a name property
// fs- and request- streams have path property
filename = path.basename(options.filename || value.name || value.path);
} else if (value.readable && Object.prototype.hasOwnProperty.call(value, 'httpVersion')) {
} else if (options.filename || (value && (value.name || value.path))) {
/*
* custom filename take precedence
* formidable and the browser add a name property
* fs- and request- streams have path property
*/
filename = path.basename(options.filename || (value && (value.name || value.path)));
} else if (value && value.readable && hasOwn(value, 'httpVersion')) {
// or try http response
filename = path.basename(value.client._httpMessage.path || '');
}
if (filename) {
contentDisposition = 'filename="' + filename + '"';
return 'filename="' + filename + '"';
}
return contentDisposition;
};
FormData.prototype._getContentType = function (value, options) {
// use custom content-type above all
var contentType = options.contentType;
// or try `name` from formidable, browser
if (!contentType && value.name) {
if (!contentType && value && value.name) {
contentType = mime.lookup(value.name);
}
// or try `path` from fs-, request- streams
if (!contentType && value.path) {
if (!contentType && value && value.path) {
contentType = mime.lookup(value.path);
}
// or if it's http-reponse
if (!contentType && value.readable && Object.prototype.hasOwnProperty.call(value, 'httpVersion')) {
if (!contentType && value && value.readable && hasOwn(value, 'httpVersion')) {
contentType = value.headers['content-type'];
}
@ -268,7 +263,7 @@ FormData.prototype._getContentType = function(value, options) {
}
// fallback to the default content type if `value` is not simple value
if (!contentType && typeof value == 'object') {
if (!contentType && value && typeof value === 'object') {
contentType = FormData.DEFAULT_CONTENT_TYPE;
}
@ -279,7 +274,7 @@ FormData.prototype._multiPartFooter = function() {
return function (next) {
var footer = FormData.LINE_BREAK;
var lastPart = (this._streams.length === 0);
var lastPart = this._streams.length === 0;
if (lastPart) {
footer += this._lastBoundary();
}
@ -298,8 +293,8 @@ FormData.prototype.getHeaders = function(userHeaders) {
'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
};
for (header in userHeaders) {
if (Object.prototype.hasOwnProperty.call(userHeaders, header)) {
for (header in userHeaders) { // eslint-disable-line no-restricted-syntax
if (hasOwn(userHeaders, header)) {
formHeaders[header.toLowerCase()] = userHeaders[header];
}
}
@ -308,6 +303,9 @@ FormData.prototype.getHeaders = function(userHeaders) {
};
FormData.prototype.setBoundary = function (boundary) {
if (typeof boundary !== 'string') {
throw new TypeError('FormData boundary must be a string');
}
this._boundary = boundary;
};
@ -320,13 +318,12 @@ FormData.prototype.getBoundary = function() {
};
FormData.prototype.getBuffer = function () {
var dataBuffer = new Buffer.alloc(0);
var dataBuffer = new Buffer.alloc(0); // eslint-disable-line new-cap
var boundary = this.getBoundary();
// Create the form content. Add Line breaks to the end of data.
for (var i = 0, len = this._streams.length; i < len; i++) {
if (typeof this._streams[i] !== 'function') {
// Add content to the buffer.
if (Buffer.isBuffer(this._streams[i])) {
dataBuffer = Buffer.concat([dataBuffer, this._streams[i]]);
@ -347,32 +344,28 @@ FormData.prototype.getBuffer = function() {
FormData.prototype._generateBoundary = function () {
// This generates a 50 character boundary similar to those used by Firefox.
// They are optimized for boyer-moore parsing.
var boundary = '--------------------------';
for (var i = 0; i < 24; i++) {
boundary += Math.floor(Math.random() * 10).toString(16);
}
this._boundary = boundary;
// They are optimized for boyer-moore parsing.
this._boundary = '--------------------------' + crypto.randomBytes(12).toString('hex');
};
// Note: getLengthSync DOESN'T calculate streams length
// As workaround one can calculate file size manually
// and add it as knownLength option
// As workaround one can calculate file size manually and add it as knownLength option
FormData.prototype.getLengthSync = function () {
var knownLength = this._overheadLength + this._valueLength;
// Don't get confused, there are 3 "internal" streams for each keyval pair
// so it basically checks if there is any value added to the form
// Don't get confused, there are 3 "internal" streams for each keyval pair so it basically checks if there is any value added to the form
if (this._streams.length) {
knownLength += this._lastBoundary().length;
}
// https://github.com/form-data/form-data/issues/40
if (!this.hasKnownLength()) {
// Some async length retrievers are present
// therefore synchronous length calculation is false.
// Please use getLength(callback) to get proper length
/*
* Some async length retrievers are present
* therefore synchronous length calculation is false.
* Please use getLength(callback) to get proper length
*/
this._error(new Error('Cannot calculate proper length in synchronous way.'));
}
@ -419,30 +412,25 @@ FormData.prototype.getLength = function(cb) {
};
FormData.prototype.submit = function (params, cb) {
var request
, options
, defaults = {method: 'post'}
;
var request;
var options;
var defaults = { method: 'post' };
// parse provided url if it's string
// or treat it as options object
if (typeof params == 'string') {
params = parseUrl(params);
// parse provided url if it's string or treat it as options object
if (typeof params === 'string') {
params = parseUrl(params); // eslint-disable-line no-param-reassign
/* eslint sort-keys: 0 */
options = populate({
port: params.port,
path: params.pathname,
host: params.hostname,
protocol: params.protocol
}, defaults);
// use custom params
} else {
} else { // use custom params
options = populate(params, defaults);
// if no port provided use default one
if (!options.port) {
options.port = options.protocol == 'https:' ? 443 : 80;
options.port = options.protocol === 'https:' ? 443 : 80;
}
}
@ -450,7 +438,7 @@ FormData.prototype.submit = function(params, cb) {
options.headers = this.getHeaders(params.headers);
// https if specified, fallback to http in any other case
if (options.protocol == 'https:') {
if (options.protocol === 'https:') {
request = https.request(options);
} else {
request = http.request(options);
@ -476,7 +464,7 @@ FormData.prototype.submit = function(params, cb) {
request.removeListener('error', callback);
request.removeListener('response', onResponse);
return cb.call(this, error, responce);
return cb.call(this, error, responce); // eslint-disable-line no-invalid-this
};
onResponse = callback.bind(this, null);
@ -501,3 +489,6 @@ FormData.prototype.toString = function () {
return '[object FormData]';
};
setToStringTag(FormData, 'FormData');
// Public API
module.exports = FormData;

View file

@ -1,9 +1,9 @@
'use strict';
// populates missing values
module.exports = function (dst, src) {
Object.keys(src).forEach(function(prop)
{
dst[prop] = dst[prop] || src[prop];
Object.keys(src).forEach(function (prop) {
dst[prop] = dst[prop] || src[prop]; // eslint-disable-line no-param-reassign
});
return dst;

View file

@ -2,7 +2,7 @@
"author": "Felix Geisendörfer <felix@debuggable.com> (http://debuggable.com/)",
"name": "form-data",
"description": "A library to create readable \"multipart/form-data\" streams. Can be used to submit forms and file uploads to other web applications.",
"version": "4.0.2",
"version": "4.0.4",
"repository": {
"type": "git",
"url": "git://github.com/form-data/form-data.git"
@ -28,15 +28,14 @@
"files": "pkgfiles --sort=name",
"get-version": "node -e \"console.log(require('./package.json').version)\"",
"update-readme": "sed -i.bak 's/\\/master\\.svg/\\/v'$(npm --silent run get-version)'.svg/g' README.md",
"restore-readme": "mv README.md.bak README.md",
"prepublish": "in-publish && npm run update-readme || not-in-publish",
"postpublish": "npm run restore-readme"
"postupdate-readme": "mv README.md.bak READ.ME.md.bak",
"restore-readme": "mv READ.ME.md.bak README.md",
"prepublish": "not-in-publish || npm run prepublishOnly",
"prepack": "npm run update-readme",
"postpack": "npm run restore-readme",
"version": "auto-changelog && git add CHANGELOG.md",
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
},
"pre-commit": [
"lint",
"ci-test",
"check"
],
"engines": {
"node": ">= 6"
},
@ -44,17 +43,17 @@
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"devDependencies": {
"@types/combined-stream": "^1.0.6",
"@types/mime-types": "^2.1.4",
"@types/node": "^12.20.55",
"@ljharb/eslint-config": "^21.2.0",
"auto-changelog": "^2.5.0",
"browserify": "^13.3.0",
"browserify-istanbul": "^2.0.0",
"coveralls": "^3.1.1",
"cross-spawn": "^6.0.6",
"eslint": "^6.8.0",
"eslint": "=8.8.0",
"fake": "^0.2.2",
"far": "^0.0.7",
"formidable": "^1.2.6",
@ -64,11 +63,20 @@
"obake": "^0.1.2",
"pkgfiles": "^2.3.2",
"pre-commit": "^1.2.2",
"predict-v8-randomness": "^1.0.35",
"puppeteer": "^1.20.0",
"request": "~2.87.0",
"rimraf": "^2.7.1",
"tape": "^5.9.0",
"typescript": "^3.9.10"
"semver": "^6.3.1",
"tape": "^5.9.0"
},
"license": "MIT"
"license": "MIT",
"auto-changelog": {
"output": "CHANGELOG.md",
"template": "keepachangelog",
"unreleased": false,
"commitLimit": false,
"backfillLimit": false,
"hideCredit": true
}
}

90
Backend/node_modules/object-assign/index.js generated vendored Normal file
View file

@ -0,0 +1,90 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};

21
Backend/node_modules/object-assign/license generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

42
Backend/node_modules/object-assign/package.json generated vendored Normal file
View file

@ -0,0 +1,42 @@
{
"name": "object-assign",
"version": "4.1.1",
"description": "ES2015 `Object.assign()` ponyfill",
"license": "MIT",
"repository": "sindresorhus/object-assign",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "xo && ava",
"bench": "matcha bench.js"
},
"files": [
"index.js"
],
"keywords": [
"object",
"assign",
"extend",
"properties",
"es2015",
"ecmascript",
"harmony",
"ponyfill",
"prollyfill",
"polyfill",
"shim",
"browser"
],
"devDependencies": {
"ava": "^0.16.0",
"lodash": "^4.16.4",
"matcha": "^0.7.0",
"xo": "^0.16.0"
}
}

61
Backend/node_modules/object-assign/readme.md generated vendored Normal file
View file

@ -0,0 +1,61 @@
# object-assign [![Build Status](https://travis-ci.org/sindresorhus/object-assign.svg?branch=master)](https://travis-ci.org/sindresorhus/object-assign)
> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) [ponyfill](https://ponyfill.com)
## Use the built-in
Node.js 4 and up, as well as every evergreen browser (Chrome, Edge, Firefox, Opera, Safari),
support `Object.assign()` :tada:. If you target only those environments, then by all
means, use `Object.assign()` instead of this package.
## Install
```
$ npm install --save object-assign
```
## Usage
```js
const objectAssign = require('object-assign');
objectAssign({foo: 0}, {bar: 1});
//=> {foo: 0, bar: 1}
// multiple sources
objectAssign({foo: 0}, {bar: 1}, {baz: 2});
//=> {foo: 0, bar: 1, baz: 2}
// overwrites equal keys
objectAssign({foo: 0}, {foo: 1}, {foo: 2});
//=> {foo: 2}
// ignores null and undefined sources
objectAssign({foo: 0}, null, {bar: 1}, undefined);
//=> {foo: 0, bar: 1}
```
## API
### objectAssign(target, [source, ...])
Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones.
## Resources
- [ES2015 spec - Object.assign](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign)
## Related
- [deep-assign](https://github.com/sindresorhus/deep-assign) - Recursive `Object.assign()`
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)

View file

@ -10,7 +10,8 @@
"license": "ISC",
"dependencies": {
"axios": "^1.9.0",
"dotenv": "^17.0.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"express": "^5.1.0",
"mongoose": "^8.15.0"
}
@ -187,6 +188,19 @@
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@ -223,9 +237,9 @@
}
},
"node_modules/dotenv": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.0.0.tgz",
"integrity": "sha512-A0BJ5lrpJVSfnMMXjmeO0xUnoxqsBHWCoqqTnGwGYVdnctqXXUEhJOO7LxmgxJon9tEZFGpe0xPRX0h2v3AANQ==",
"version": "17.2.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
"integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@ -403,14 +417,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@ -782,6 +797,15 @@
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",

View file

@ -11,7 +11,8 @@
"description": "",
"dependencies": {
"axios": "^1.9.0",
"dotenv": "^17.0.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"express": "^5.1.0",
"mongoose": "^8.15.0"
}

View file

@ -0,0 +1,16 @@
# monarch
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.

View file

@ -1,8 +1,27 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.monarch">
<!-- ✅ Permissions (outside application) -->
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="monarch"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!-- ✅ SMS Receiver -->
<receiver android:name="com.shounakmulay.telephony.sms.SmsReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<activity
android:name=".MainActivity"
android:exported="true"
@ -12,30 +31,22 @@
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"
/>
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 -->
<!-- Flutter plugin metadata -->
<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. -->
<!-- Flutter Process Text Plugin support -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT" />

View file

@ -4,8 +4,10 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:monarch/enviroment.dart';
import 'package:monarch/statistics.dart';
class AddExpenseScreen extends StatefulWidget {
@ -104,7 +106,9 @@ class _AddExpenseScreenState extends State<AddExpenseScreen>
// Ensure only one decimal point
List<String> parts = cleanValue.split('.');
if (parts.length > 2) {
cleanValue = '₹{parts[0]}.₹{parts.sublist(1).join('')}';
cleanValue =
'₹{parts[0]}.₹{parts.sublist(1).join('
')}';
}
if (cleanValue.isNotEmpty) {
@ -173,6 +177,7 @@ class _AddExpenseScreenState extends State<AddExpenseScreen>
),
);
}
final baseUrl = dotenv.env['BASE_URL'];
Future<void> addTransaction() async {
// Validation first
@ -230,7 +235,7 @@ class _AddExpenseScreenState extends State<AddExpenseScreen>
try {
final response = await http.post(
Uri.parse('http://192.168.1.9:3000/api/transaction/add'),
Uri.parse('${Environment.baseUrl}/api/transaction/add'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'description': descriptionController.text,

View file

@ -0,0 +1,3 @@
class Environment {
static const String baseUrl = 'http://10.231.12.247:3000';
}

View file

@ -2,10 +2,11 @@
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'enviroment.dart';
Future<List<Map<String, dynamic>>> fetchRecentTransactions() async {
final response = await http.get(
Uri.parse('http://192.168.1.9:3000/api/transactions/recent'),
Uri.parse('${Environment.baseUrl}/api/transactions/recent'),
);
if (response.statusCode == 200) {

View file

@ -1,80 +0,0 @@
// ignore_for_file: library_private_types_in_public_api
import 'package:flutter/material.dart';
class AnimationControllerPage extends StatefulWidget {
final Function(Animation<Offset>) onAnimationCreated;
final Function(Animation<double>) onFadeAnimationCreated;
const AnimationControllerPage({super.key, required this.onAnimationCreated, required this.onFadeAnimationCreated, required Center child});
@override
_AnimationControllerPageState createState() => _AnimationControllerPageState();
}
class _AnimationControllerPageState extends State<AnimationControllerPage> with TickerProviderStateMixin {
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(parent: _fadeController, curve: Curves.easeOut));
_slideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(
CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic),
);
// Start animations
_fadeController.forward();
_slideController.forward();
widget.onAnimationCreated(_slideAnimation);
widget.onFadeAnimationCreated(_fadeAnimation);
}
@override
void dispose() {
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
),
),
);
}
}

View file

@ -3,17 +3,19 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
import 'package:monarch/add.dart';
import 'package:monarch/update_budget.dart';
import 'package:monarch/homepage.dart';
//import 'package:monarch/homepage.dart';
import 'package:monarch/statistics.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized(); // This fixes the issue
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@ -37,6 +39,8 @@ class AddTransactionPage extends StatefulWidget {
class _AddTransactionPageState extends State<AddTransactionPage> {
final TextEditingController descriptionController = TextEditingController();
final TextEditingController amountController = TextEditingController();
final baseUrl = dotenv.env['BASE_URL'];
Future<void> addTransaction() async {
// Show loading indicator
showDialog(
@ -47,7 +51,7 @@ class _AddTransactionPageState extends State<AddTransactionPage> {
try {
final response = await http.post(
Uri.parse('http://192.168.1.9:3000/api/transaction/add'),
Uri.parse('$baseUrl/api/transaction/add'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'description': descriptionController.text,

View file

@ -4,9 +4,11 @@ import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:monarch/add.dart';
import 'package:monarch/enviroment.dart';
import 'package:monarch/update_budget.dart';
import 'package:monarch/budget_manager.dart';
import 'package:monarch/homepage.dart';
@ -58,7 +60,6 @@ class StatisticsState extends State<Statistics> with TickerProviderStateMixin {
];
String selectedCategory = 'All';
Map<String, double> totalAmountPerCategory = {};
// Color Scheme
final Color backgroundColor = const Color(0xFFF8F9FA);
final Color primaryColor = const Color(0xFF2D3436);
@ -108,7 +109,9 @@ class StatisticsState extends State<Statistics> with TickerProviderStateMixin {
Future<void> fetchTransactions({String category = 'All'}) async {
setState(() => isLoading = true);
try {
final uri = Uri.parse('http://192.168.1.9:3000/api/transactions').replace(
final uri = Uri.parse(
'${Environment.baseUrl}/api/transactions',
).replace(
queryParameters: category == 'All' ? null : {'category': category},
);
final response = await http.get(uri);

1
Frontend/monarch/linux/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
flutter/ephemeral

View file

@ -0,0 +1,128 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "monarch")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.monarch")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

View file

@ -0,0 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

View file

@ -0,0 +1,11 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void fl_register_plugins(FlPluginRegistry* registry) {
}

View file

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

View file

@ -0,0 +1,23 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View file

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the application ID.
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")

View file

@ -0,0 +1,6 @@
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}

View file

@ -0,0 +1,130 @@
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include "flutter/generated_plugin_registrant.h"
struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
};
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
MyApplication* self = MY_APPLICATION(application);
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
#endif
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "monarch");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "monarch");
}
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}
// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}
g_application_activate(application);
*exit_status = 0;
return TRUE;
}
// Implements GApplication::startup.
static void my_application_startup(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application startup.
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
}
// Implements GApplication::shutdown.
static void my_application_shutdown(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application shutdown.
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
}
// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}
static void my_application_init(MyApplication* self) {}
MyApplication* my_application_new() {
// Set the program name to the application ID, which helps various systems
// like GTK and desktop environments map this running application to its
// corresponding .desktop file. This ensures better integration by allowing
// the application to be recognized beyond its binary name.
g_set_prgname(APPLICATION_ID);
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
"flags", G_APPLICATION_NON_UNIQUE,
nullptr));
}

View file

@ -0,0 +1,18 @@
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_

7
Frontend/monarch/macos/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View file

@ -0,0 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import path_provider_foundation
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View file

@ -0,0 +1,705 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC10EC2044A3C60003C045;
remoteInfo = Runner;
};
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* monarch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "monarch.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
331C80D2294CF70F00263BE5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C80D6294CF71000263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C80D7294CF71000263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* monarch.app */,
331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C80D4294CF70F00263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C80DA294CF71000263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* monarch.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 33CC10EC2044A3C60003C045;
};
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
331C80D4294CF70F00263BE5 /* RunnerTests */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C80D3294CF70F00263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C80D1294CF70F00263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC10EC2044A3C60003C045 /* Runner */;
targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
};
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.monarch.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monarch.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monarch";
};
name = Debug;
};
331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.monarch.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monarch.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monarch";
};
name = Release;
};
331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.monarch.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monarch.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monarch";
};
name = Profile;
};
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
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_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
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_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
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_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C80DB294CF71000263BE5 /* Debug */,
331C80DC294CF71000263BE5 /* Release */,
331C80DD294CF71000263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -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>

View file

@ -0,0 +1,99 @@
<?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 = "33CC10EC2044A3C60003C045"
BuildableName = "monarch.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 = "33CC10EC2044A3C60003C045"
BuildableName = "monarch.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "monarch.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 = "33CC10EC2044A3C60003C045"
BuildableName = "monarch.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -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>

View file

@ -0,0 +1,13 @@
import Cocoa
import FlutterMacOS
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,343 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="EPT-qC-fAb">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>

View file

@ -0,0 +1,14 @@
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = monarch
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.monarch
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved.

View file

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"

View file

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"

View file

@ -0,0 +1,13 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES

View file

@ -0,0 +1,12 @@
<?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>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,32 @@
<?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>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,15 @@
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

View file

@ -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>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,12 @@
import Cocoa
import FlutterMacOS
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.
}
}

View file

@ -102,6 +102,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_dotenv:
dependency: "direct main"
description:
name: flutter_dotenv
sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b
url: "https://pub.dev"
source: hosted
version: "5.2.1"
flutter_lints:
dependency: "direct dev"
description:

View file

@ -16,6 +16,8 @@ dependencies:
fl_chart: ^1.0.0
google_fonts: ^6.2.1
shared_preferences: ^2.5.3
flutter_dotenv: ^5.2.1
dev_dependencies:
flutter_test:

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="monarch">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>monarch</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>

View file

@ -0,0 +1,35 @@
{
"name": "monarch",
"short_name": "monarch",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}

17
Frontend/monarch/windows/.gitignore vendored Normal file
View file

@ -0,0 +1,17 @@
flutter/ephemeral/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

View file

@ -0,0 +1,108 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
project(monarch LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "monarch")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(VERSION 3.14...3.25)
# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
endif()
# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release
COMPONENT Runtime)

View file

@ -0,0 +1,109 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.14)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# Set fallback configurations for older versions of the flutter tool.
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
set(FLUTTER_TARGET_PLATFORM "windows-x64")
endif()
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"flutter_windows.h"
"flutter_messenger.h"
"flutter_plugin_registrar.h"
"flutter_texture_registrar.h"
)
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc"
"standard_codec.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_view_controller.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
)
apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP}
)
apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_app flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
${PHONY_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)

View file

@ -0,0 +1,11 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}

View file

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

View file

@ -0,0 +1,23 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View file

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.14)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
"utils.cpp"
"win32_window.cpp"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
"Runner.rc"
"runner.exe.manifest"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the build version.
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
# Disable Windows macros that collide with C++ standard library functions.
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
# Add dependency libraries and include directories. Add any application-specific
# dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)

View file

@ -0,0 +1,121 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP_ICON ICON "resources\\app_icon.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else
#define VERSION_AS_NUMBER 1,0,0,0
#endif
#if defined(FLUTTER_VERSION)
#define VERSION_AS_STRING FLUTTER_VERSION
#else
#define VERSION_AS_STRING "1.0.0"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_AS_NUMBER
PRODUCTVERSION VERSION_AS_NUMBER
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "com.example" "\0"
VALUE "FileDescription", "monarch" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "monarch" "\0"
VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0"
VALUE "OriginalFilename", "monarch.exe" "\0"
VALUE "ProductName", "monarch" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,71 @@
#include "flutter_window.h"
#include <optional>
#include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
: project_(project) {}
FlutterWindow::~FlutterWindow() {}
bool FlutterWindow::OnCreate() {
if (!Win32Window::OnCreate()) {
return false;
}
RECT frame = GetClientArea();
// The size here must match the window dimensions to avoid unnecessary surface
// creation / destruction in the startup path.
flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
frame.right - frame.left, frame.bottom - frame.top, project_);
// Ensure that basic setup of the controller was successful.
if (!flutter_controller_->engine() || !flutter_controller_->view()) {
return false;
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
flutter_controller_->ForceRedraw();
return true;
}
void FlutterWindow::OnDestroy() {
if (flutter_controller_) {
flutter_controller_ = nullptr;
}
Win32Window::OnDestroy();
}
LRESULT
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
// Give Flutter, including plugins, an opportunity to handle window messages.
if (flutter_controller_) {
std::optional<LRESULT> result =
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
lparam);
if (result) {
return *result;
}
}
switch (message) {
case WM_FONTCHANGE:
flutter_controller_->engine()->ReloadSystemFonts();
break;
}
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}

View file

@ -0,0 +1,33 @@
#ifndef RUNNER_FLUTTER_WINDOW_H_
#define RUNNER_FLUTTER_WINDOW_H_
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <memory>
#include "win32_window.h"
// A window that does nothing but host a Flutter view.
class FlutterWindow : public Win32Window {
public:
// Creates a new FlutterWindow hosting a Flutter view running |project|.
explicit FlutterWindow(const flutter::DartProject& project);
virtual ~FlutterWindow();
protected:
// Win32Window:
bool OnCreate() override;
void OnDestroy() override;
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept override;
private:
// The project to run.
flutter::DartProject project_;
// The Flutter instance hosted by this window.
std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
};
#endif // RUNNER_FLUTTER_WINDOW_H_

View file

@ -0,0 +1,43 @@
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include "flutter_window.h"
#include "utils.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"monarch", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::CoUninitialize();
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Runner.rc
//
#define IDI_APP_ICON 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View file

@ -0,0 +1,65 @@
#include "utils.h"
#include <flutter_windows.h>
#include <io.h>
#include <stdio.h>
#include <windows.h>
#include <iostream>
void CreateAndAttachConsole() {
if (::AllocConsole()) {
FILE *unused;
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
_dup2(_fileno(stdout), 1);
}
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
_dup2(_fileno(stdout), 2);
}
std::ios::sync_with_stdio();
FlutterDesktopResyncOutputStreams();
}
}
std::vector<std::string> GetCommandLineArguments() {
// Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
int argc;
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
if (argv == nullptr) {
return std::vector<std::string>();
}
std::vector<std::string> command_line_arguments;
// Skip the first argument as it's the binary name.
for (int i = 1; i < argc; i++) {
command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
}
::LocalFree(argv);
return command_line_arguments;
}
std::string Utf8FromUtf16(const wchar_t* utf16_string) {
if (utf16_string == nullptr) {
return std::string();
}
unsigned int target_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-1, nullptr, 0, nullptr, nullptr)
-1; // remove the trailing null character
int input_length = (int)wcslen(utf16_string);
std::string utf8_string;
if (target_length == 0 || target_length > utf8_string.max_size()) {
return utf8_string;
}
utf8_string.resize(target_length);
int converted_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
input_length, utf8_string.data(), target_length, nullptr, nullptr);
if (converted_length == 0) {
return std::string();
}
return utf8_string;
}

View file

@ -0,0 +1,19 @@
#ifndef RUNNER_UTILS_H_
#define RUNNER_UTILS_H_
#include <string>
#include <vector>
// Creates a console for the process, and redirects stdout and stderr to
// it for both the runner and the Flutter library.
void CreateAndAttachConsole();
// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
// encoded in UTF-8. Returns an empty std::string on failure.
std::string Utf8FromUtf16(const wchar_t* utf16_string);
// Gets the command line arguments passed in as a std::vector<std::string>,
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
std::vector<std::string> GetCommandLineArguments();
#endif // RUNNER_UTILS_H_

View file

@ -0,0 +1,288 @@
#include "win32_window.h"
#include <dwmapi.h>
#include <flutter_windows.h>
#include "resource.h"
namespace {
/// Window attribute that enables dark mode window decorations.
///
/// Redefined in case the developer's machine has a Windows SDK older than
/// version 10.0.22000.0.
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
/// Registry key for app theme preference.
///
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
/// value indicates apps should use light mode.
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
// Scale helper to convert logical scaler values to physical using passed in
// scale factor
int Scale(int source, double scale_factor) {
return static_cast<int>(source * scale_factor);
}
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
// This API is only needed for PerMonitor V1 awareness mode.
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
HMODULE user32_module = LoadLibraryA("User32.dll");
if (!user32_module) {
return;
}
auto enable_non_client_dpi_scaling =
reinterpret_cast<EnableNonClientDpiScaling*>(
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
}
FreeLibrary(user32_module);
}
} // namespace
// Manages the Win32Window's window class registration.
class WindowClassRegistrar {
public:
~WindowClassRegistrar() = default;
// Returns the singleton registrar instance.
static WindowClassRegistrar* GetInstance() {
if (!instance_) {
instance_ = new WindowClassRegistrar();
}
return instance_;
}
// Returns the name of the window class, registering the class if it hasn't
// previously been registered.
const wchar_t* GetWindowClass();
// Unregisters the window class. Should only be called if there are no
// instances of the window.
void UnregisterWindowClass();
private:
WindowClassRegistrar() = default;
static WindowClassRegistrar* instance_;
bool class_registered_ = false;
};
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
const wchar_t* WindowClassRegistrar::GetWindowClass() {
if (!class_registered_) {
WNDCLASS window_class{};
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
window_class.lpszClassName = kWindowClassName;
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = GetModuleHandle(nullptr);
window_class.hIcon =
LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
window_class.hbrBackground = 0;
window_class.lpszMenuName = nullptr;
window_class.lpfnWndProc = Win32Window::WndProc;
RegisterClass(&window_class);
class_registered_ = true;
}
return kWindowClassName;
}
void WindowClassRegistrar::UnregisterWindowClass() {
UnregisterClass(kWindowClassName, nullptr);
class_registered_ = false;
}
Win32Window::Win32Window() {
++g_active_window_count;
}
Win32Window::~Win32Window() {
--g_active_window_count;
Destroy();
}
bool Win32Window::Create(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
WindowClassRegistrar::GetInstance()->GetWindowClass();
const POINT target_point = {static_cast<LONG>(origin.x),
static_cast<LONG>(origin.y)};
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!window) {
return false;
}
UpdateTheme(window);
return OnCreate();
}
bool Win32Window::Show() {
return ShowWindow(window_handle_, SW_SHOWNORMAL);
}
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
if (message == WM_NCCREATE) {
auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
EnableFullDpiSupportIfAvailable(window);
that->window_handle_ = window;
} else if (Win32Window* that = GetThisFromHandle(window)) {
return that->MessageHandler(window, message, wparam, lparam);
}
return DefWindowProc(window, message, wparam, lparam);
}
LRESULT
Win32Window::MessageHandler(HWND hwnd,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
switch (message) {
case WM_DESTROY:
window_handle_ = nullptr;
Destroy();
if (quit_on_close_) {
PostQuitMessage(0);
}
return 0;
case WM_DPICHANGED: {
auto newRectSize = reinterpret_cast<RECT*>(lparam);
LONG newWidth = newRectSize->right - newRectSize->left;
LONG newHeight = newRectSize->bottom - newRectSize->top;
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
case WM_SIZE: {
RECT rect = GetClientArea();
if (child_content_ != nullptr) {
// Size and position the child window.
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
}
return 0;
}
case WM_ACTIVATE:
if (child_content_ != nullptr) {
SetFocus(child_content_);
}
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
}
void Win32Window::Destroy() {
OnDestroy();
if (window_handle_) {
DestroyWindow(window_handle_);
window_handle_ = nullptr;
}
if (g_active_window_count == 0) {
WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
}
}
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
return reinterpret_cast<Win32Window*>(
GetWindowLongPtr(window, GWLP_USERDATA));
}
void Win32Window::SetChildContent(HWND content) {
child_content_ = content;
SetParent(content, window_handle_);
RECT frame = GetClientArea();
MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
frame.bottom - frame.top, true);
SetFocus(child_content_);
}
RECT Win32Window::GetClientArea() {
RECT frame;
GetClientRect(window_handle_, &frame);
return frame;
}
HWND Win32Window::GetHandle() {
return window_handle_;
}
void Win32Window::SetQuitOnClose(bool quit_on_close) {
quit_on_close_ = quit_on_close;
}
bool Win32Window::OnCreate() {
// No-op; provided for subclasses.
return true;
}
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
void Win32Window::UpdateTheme(HWND const window) {
DWORD light_mode;
DWORD light_mode_size = sizeof(light_mode);
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
kGetPreferredBrightnessRegValue,
RRF_RT_REG_DWORD, nullptr, &light_mode,
&light_mode_size);
if (result == ERROR_SUCCESS) {
BOOL enable_dark_mode = light_mode == 0;
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
&enable_dark_mode, sizeof(enable_dark_mode));
}
}

View file

@ -0,0 +1,102 @@
#ifndef RUNNER_WIN32_WINDOW_H_
#define RUNNER_WIN32_WINDOW_H_
#include <windows.h>
#include <functional>
#include <memory>
#include <string>
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
// inherited from by classes that wish to specialize with custom
// rendering and input handling
class Win32Window {
public:
struct Point {
unsigned int x;
unsigned int y;
Point(unsigned int x, unsigned int y) : x(x), y(y) {}
};
struct Size {
unsigned int width;
unsigned int height;
Size(unsigned int width, unsigned int height)
: width(width), height(height) {}
};
Win32Window();
virtual ~Win32Window();
// Creates a win32 window with |title| that is positioned and sized using
// |origin| and |size|. New windows are created on the default monitor. Window
// sizes are specified to the OS in physical pixels, hence to ensure a
// consistent size this function will scale the inputted width and height as
// as appropriate for the default monitor. The window is invisible until
// |Show| is called. Returns true if the window was created successfully.
bool Create(const std::wstring& title, const Point& origin, const Size& size);
// Show the current window. Returns true if the window was successfully shown.
bool Show();
// Release OS resources associated with window.
void Destroy();
// Inserts |content| into the window tree.
void SetChildContent(HWND content);
// Returns the backing Window handle to enable clients to set icon and other
// window properties. Returns nullptr if the window has been destroyed.
HWND GetHandle();
// If true, closing this window will quit the application.
void SetQuitOnClose(bool quit_on_close);
// Return a RECT representing the bounds of the current client area.
RECT GetClientArea();
protected:
// Processes and route salient window messages for mouse handling,
// size change and DPI. Delegates handling of these to member overloads that
// inheriting classes can handle.
virtual LRESULT MessageHandler(HWND window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
// Called when CreateAndShow is called, allowing subclass window-related
// setup. Subclasses should return false if setup fails.
virtual bool OnCreate();
// Called when Destroy is called.
virtual void OnDestroy();
private:
friend class WindowClassRegistrar;
// OS callback called by message pump. Handles the WM_NCCREATE message which
// is passed when the non-client area is being created and enables automatic
// non-client DPI scaling so that the non-client area automatically
// responds to changes in DPI. All other messages are handled by
// MessageHandler.
static LRESULT CALLBACK WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
// Update the window frame's theme to match the system theme.
static void UpdateTheme(HWND const window);
bool quit_on_close_ = false;
// window handle for top level window.
HWND window_handle_ = nullptr;
// window handle for hosted content.
HWND child_content_ = nullptr;
};
#endif // RUNNER_WIN32_WINDOW_H_