Merge branch 'develop' into modular-generation

This commit is contained in:
Simon Binder 2022-08-30 21:20:32 +02:00
commit 2575f36e82
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
197 changed files with 6098 additions and 297 deletions

View File

@ -8,7 +8,7 @@ We use a static site generator based on `build_runner` to build the documentatio
For a fast edit-refresh cycle, run
```
dart pub global run webdev serve --auto refresh pages:9999 web:8080
dart pub global run webdev serve --auto refresh pages:9999 test:10000 web:8080
```
You can ignore the `pages:9999` (or use any other port), it's just required

View File

@ -1,7 +1,43 @@
import 'package:drift/drift.dart';
import 'tables/filename.dart';
// #docregion joinIntro
// We define a data class to contain both a todo entry and the associated
// category.
class EntryWithCategory {
EntryWithCategory(this.entry, this.category);
final Todo entry;
final Category? category;
}
// #enddocregion joinIntro
extension GroupByQueries on MyDatabase {
// #docregion joinIntro
// in the database class, we can then load the category for each entry
Stream<List<EntryWithCategory>> entriesWithCategory() {
final query = select(todos).join([
leftOuterJoin(categories, categories.id.equalsExp(todos.category)),
]);
// see next section on how to parse the result
// #enddocregion joinIntro
// #docregion results
return query.watch().map((rows) {
return rows.map((row) {
return EntryWithCategory(
row.readTable(todos),
row.readTableOrNull(categories),
);
}).toList();
});
// #enddocregion results
// #docregion joinIntro
}
// #enddocregion joinIntro
// #docregion countTodosInCategories
Future<void> countTodosInCategories() async {
final amountOfTodos = todos.id.count();
@ -34,4 +70,28 @@ extension GroupByQueries on MyDatabase {
return query.map((row) => row.read(avgLength)!).watchSingle();
}
// #enddocregion averageItemLength
// #docregion otherTodosInSameCategory
/// Searches for todo entries in the same category as the ones having
/// `titleQuery` in their titles.
Future<List<Todo>> otherTodosInSameCategory(String titleQuery) async {
// Since we're adding the same table twice (once to filter for the title,
// and once to find other todos in same category), we need a way to
// distinguish the two tables. So, we're giving one of them a special name:
final otherTodos = alias(todos, 'inCategory');
final query = select(otherTodos).join([
// In joins, `useColumns: false` tells drift to not add columns of the
// joined table to the result set. This is useful here, since we only join
// the tables so that we can refer to them in the where clause.
innerJoin(categories, categories.id.equalsExp(otherTodos.category),
useColumns: false),
innerJoin(todos, todos.category.equalsExp(categories.id),
useColumns: false),
])
..where(todos.title.contains(titleQuery));
return query.map((row) => row.readTable(otherTodos)).get();
}
// #enddocregion otherTodosInSameCategory
}

View File

@ -1,7 +1,8 @@
// ignore_for_file: directives_ordering
// #docregion open
// These imports are only needed to open the database
// To open the database, add these imports to the existing file defining the
// database class. They are used to open the database.
import 'dart:io';
import 'package:drift/native.dart';
@ -62,3 +63,19 @@ LazyDatabase _openConnection() {
return NativeDatabase(file);
});
}
// #enddocregion open
// #docregion usage
Future<void> main() async {
final database = MyDatabase();
// Simple insert:
await database
.into(database.categories)
.insert(CategoriesCompanion.insert(description: 'my first category'));
// Simple select:
final allCategories = await database.select(database.categories).get();
print('Categories in database: $allCategories');
}
// #enddocregion usage

View File

@ -130,7 +130,7 @@ targets:
modules:
- json1
- fts5
- moor_ffi
- math
```
We currently support the following extensions:
@ -138,6 +138,9 @@ We currently support the following extensions:
- [json1](https://www.sqlite.org/json1.html): Support static analysis for `json_` functions in moor files
- [fts5](https://www.sqlite.org/fts5.html): Support `CREATE VIRTUAL TABLE` statements for `fts5` tables and the `MATCH` operator.
Functions like `highlight` or `bm25` are available as well.
- `rtree`: Static analysis support for the [R*Tree](https://www.sqlite.org/rtree.html) extension.
Enabling this option is safe when using a `NativeDatabase` with `sqlite3_flutter_libs`,
which compiles sqlite3 with the R*Tree extension enabled.
- `moor_ffi`: Enables support for functions that are only available when using a `NativeDatabase`. This contains `pow`, `sqrt` and a variety
of trigonometric functions. Details on those functions are available [here]({{ "../Other engines/vm.md#moor-only-functions" | pageUrl }}).
- `math`: Assumes that sqlite3 was compiled with [math functions](https://www.sqlite.org/lang_mathfunc.html).

View File

@ -8,6 +8,8 @@ aliases:
template: layouts/docs/single
---
{% assign snippets = 'package:drift_docs/snippets/queries.dart.excerpt.json' | readString | json_decode %}
## Joins
Drift supports sql joins to write queries that operate on more than one table. To use that feature, start
@ -15,24 +17,11 @@ a select regular select statement with `select(table)` and then add a list of jo
inner and left outer joins, a `ON` expression needs to be specified. Here's an example using the tables
defined in the [example]({{ "../Getting started/index.md" | pageUrl }}).
```dart
// we define a data class to contain both a todo entry and the associated category
class EntryWithCategory {
EntryWithCategory(this.entry, this.category);
{% include "blocks/snippet" snippets = snippets name = 'joinIntro' %}
final TodoEntry entry;
final Category category;
}
Of course, you can also join multiple tables:
// in the database class, we can then load the category for each entry
Stream<List<EntryWithCategory>> entriesWithCategory() {
final query = select(todos).join([
leftOuterJoin(categories, categories.id.equalsExp(todos.category)),
]);
// see next section on how to parse the result
}
```
{% include "blocks/snippet" snippets = snippets name = 'otherTodosInSameCategory' %}
## Parsing results
@ -42,16 +31,8 @@ read. It contains a `rawData` getter to obtain the raw columns. But more importa
`readTable` method can be used to read a data class from a table.
In the example query above, we can read the todo entry and the category from each row like this:
```dart
return query.watch().map((rows) {
return rows.map((row) {
return EntryWithCategory(
row.readTable(todos),
row.readTableOrNull(categories),
);
}).toList();
});
```
{% include "blocks/snippet" snippets = snippets name = 'results' %}
_Note_: `readTable` will throw an `ArgumentError` when a table is not present in the row. For instance,
todo entries might not be in any category. To account for that, we use `row.readTableOrNull` to load
@ -174,8 +155,6 @@ with the right table by default).
## Group by
{% assign snippets = 'package:drift_docs/snippets/queries.dart.excerpt.json' | readString | json_decode %}
Sometimes, you need to run queries that _aggregate_ data, meaning that data you're interested in
comes from multiple rows. Common questions include

View File

@ -44,6 +44,7 @@ to perform that work just before your drift database is opened:
```dart
import 'package:drift/drift.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path/path.dart' as p;
LazyDatabase _openConnection() {
return LazyDatabase(() async {

View File

@ -6,11 +6,45 @@ data:
template: layouts/docs/list
---
For a full example of a cross-platform Flutter app using drift following best
practices, see [app example](https://github.com/simolus3/drift/tree/develop/examples/app) in drift's repository.
For interested users wanting to take a look at how to use drift in a Flutter app
with a modern architecture, this is perhaps the best example to use as a starting
point.
We have an [example in the repo](https://github.com/simolus3/drift/tree/master/moor_flutter/example), it's a simple todo list app,
written with drift. [Rody Davis](https://github.com/rodydavis) has built a cleaner version of the example that works on all
Flutter platforms - including Web and Desktop! You can check it out [here](https://github.com/rodydavis/moor_shared).
An updated version of this example is also present in drift's [repository](https://github.com/simolus3/drift/tree/develop/examples/app).
[Abdelrahman Mostafa Elmarakby](https://github.com/abdelrahmanelmarakby) wrote an animated version of the todo app available [here](https://github.com/abdelrahmanelmarakby/todo_with_moor_and_animation).
Drift's repository also contains a number of smaller examples showcasing select
drift features:
The [HackerNews reader app](https://github.com/filiph/hn_app) from the [Boring Flutter Show](https://www.youtube.com/playlist?list=PLjxrf2q8roU3ahJVrSgAnPjzkpGmL9Czl) also uses drift to keep a list of favorite articles.
- The [encryption] example contains a simple Flutter app using an encrypted drift
database, powered by the `sqlcipher_flutter_libs` package.
- [web_worker] and [flutter_web_worker] are small web-only apps using drift in
a shared web worker, which allows for a real-time synchronization of the
database across tabs. Of course, this pattern can only be embedded into
multi-platform apps.
- The [migration] example makes use of advanced schema migrations and shows how
to test migrations between different database schemas by using drift's
[dedicated tooling][migration tooling] for this purpose.
- [Another example][with_built_value] shows how to use drift-generated code in
other builders (here, `built_value`).
Additional examples from our awesome community are available as well:
- [Abdelrahman Mostafa Elmarakby](https://github.com/abdelrahmanelmarakby) wrote an animated version of the todo app available [here](https://github.com/abdelrahmanelmarakby/todo_with_moor_and_animation).
- The [HackerNews reader app](https://github.com/filiph/hn_app) from the [Boring Flutter Show](https://www.youtube.com/playlist?list=PLjxrf2q8roU3ahJVrSgAnPjzkpGmL9Czl)
also uses drift to keep a list of favorite articles.
If you too have an open-source application using drift, feel free to reach out
and have it added to this list!
If you are interested in seeing more drift examples, or want to contribute more
examples yourself, don't hesitate to open an issue either.
Providing more up-to-date examples would be a much appreciated contribution!
Additional patterns are also shown and explained on this website:
[encryption]: https://github.com/simolus3/drift/tree/develop/examples/encryption
[web_worker]: https://github.com/simolus3/drift/tree/develop/examples/web_worker_example
[flutter_web_worker]: https://github.com/simolus3/drift/tree/develop/examples/flutter_web_worker_example
[migration]: https://github.com/simolus3/drift/tree/develop/examples/migrations_example
[migration tooling]: {{ '../Advanced Features/migrations.md#verifying-migrations' | pageUrl }}
[with_built_value]: https://github.com/simolus3/drift/tree/develop/examples/with_built_value

View File

@ -48,7 +48,9 @@ If you're wondering why so many packages are necessary, here's a quick overview
### Declaring tables
Using drift, you can model the structure of your tables with simple dart code:
Using drift, you can model the structure of your tables with simple dart code.
Let's write a file (simply called `filename.dart` in this snippet) containing
two simple tables and a database class using drift to get started:
{% include "blocks/snippet" snippets = snippets name = "overview" %}
@ -58,15 +60,25 @@ operator and can't contain anything more than what's included in the documentati
examples. Otherwise, the generator won't be able to know what's going on.
## Generating the code
Drift integrates with Dart's `build` system, so you can generate all the code needed with
`flutter pub run build_runner build`. If you want to continuously rebuild the generated code
where you change your code, run `flutter pub run build_runner watch` instead.
After running either command once, the drift generator will have created a class for your
database and data classes for your entities. To use it, change the `MyDatabase` class as
follows:
After running either command once, drift's generator will have created a class for your
database and data classes for your entities. To use it, change the `MyDatabase` class
defined in the earlier snippet as follows:
{% include "blocks/snippet" snippets = snippets name = "open" %}
That's it! You can now use drift by creating an instance of `MyDatabase`.
In a simple app from a `main` entrypoint, this may look like the following:
{% include "blocks/snippet" snippets = snippets name = "usage" %}
The articles linked below explain how to use the database in actual, complete
Flutter apps.
A complete example for a Flutter app using drift is also available [here](https://github.com/simolus3/drift/tree/develop/examples/app).
## Next steps
Congratulations! You're now ready to use all of drift. See the articles below for further reading.

View File

@ -6,16 +6,21 @@ template: layouts/docs/single
---
There are two ways to use drift on encrypted databases.
The `encrypted_moor` package is similar to `moor_flutter` and uses a platform plugin written in
The `encrypted_drift` package is similar to `drift_sqflite` and uses a platform plugin written in
Java.
Alternatively, you can use the ffi-based implementation with the `sqlcipher_flutter_libs` package.
## Using `encrypted_moor`
For new apps, we recommend using `sqlcipher_flutter_libs` with a `NativeDatabase`
from drift.
An example of a Flutter app using the new encryption package is available
[here](https://github.com/simolus3/drift/tree/develop/examples/encryption).
Starting from 1.7, we have a version of drift that can work with encrypted databases by using the
## Using `encrypted_drift`
The drift repository provides a version of drift that can work with encrypted databases by using the
[sqflite_sqlcipher](https://pub.dev/packages/sqflite_sqlcipher) library
by [@davidmartos96](https://github.com/davidmartos96). To use it, you need to
remove the dependency on `moor_flutter` from your `pubspec.yaml` and replace it
remove the dependency on `drift_sqflite` from your `pubspec.yaml` and replace it
with this:
{% assign versions = 'package:drift_docs/versions.json' | readString | json_decode %}
@ -23,16 +28,16 @@ with this:
```yaml
dependencies:
drift: ^{{ versions.drift }}
encrypted_moor:
encrypted_drift:
git:
url: https://github.com/simolus3/drift.git
path: extras/encryption
```
Instead of importing `package:moor_flutter/moor_flutter` (or `package:drift/native.dart`) in your apps,
you would then import both `package:drift/drift.dart` and `package:encrypted_moor/encrypted_moor.dart`.
Instead of importing `package:drift_sqflite/drift_sqflite.dart` (or `package:drift/native.dart`) in your apps,
you would then import both `package:drift/drift.dart` and `package:encrypted_drift/encrypted_drift.dart`.
Finally, you can replace `FlutterQueryExecutor` (or a `NativeDatabase`) with an `EncryptedExecutor`.
Finally, you can replace `SqfliteQueryExecutor` (or a `NativeDatabase`) with an `EncryptedExecutor`.
### Extra setup on Android and iOS

View File

@ -1,3 +1,10 @@
## 2.1.0
- Improve stack traces when using `watchSingle()` with a stream emitting a non-
singleton list at some point.
- Add `OrderingTerm.nulls` to control the `NULLS FIRST` or `NULLS LAST` clause
in Dart.
## 2.0.2+1
- Revert the breaking change around `QueryRow.read` only returning non-nullable

View File

@ -3,16 +3,28 @@ part of '../query_builder.dart';
/// Describes how to order rows
enum OrderingMode {
/// Ascending ordering mode (lowest items first)
asc,
asc._('ASC'),
/// Descending ordering mode (highest items first)
desc
desc._('DESC');
final String _mode;
const OrderingMode._(this._mode);
}
const _modeToString = {
OrderingMode.asc: 'ASC',
OrderingMode.desc: 'DESC',
};
/// Describes how to order nulls
enum NullsOrder {
/// Place NULLs at the start
first._('NULLS FIRST'),
/// Place NULLs at the end
last._('NULLS LAST');
final String _order;
const NullsOrder._(this._order);
}
/// A single term in a [OrderBy] clause. The priority of this term is determined
/// by its position in [OrderBy.terms].
@ -23,18 +35,40 @@ class OrderingTerm extends Component {
/// The ordering mode (ascending or descending).
final OrderingMode mode;
/// Creates an ordering term by the [expression] and the [mode] (defaults to
/// ascending).
OrderingTerm({required this.expression, this.mode = OrderingMode.asc});
/// How to order NULLs.
/// When [nulls] is [null], then it's ignored.
///
/// Note that this feature are only available in sqlite3 version `3.30.0` and
/// newer. When using `sqlite3_flutter_libs` or a web database, this is not
/// a problem.
final NullsOrder? nulls;
/// Creates an ordering term that sorts for ascending values of [expression].
factory OrderingTerm.asc(Expression expression) {
return OrderingTerm(expression: expression, mode: OrderingMode.asc);
/// Creates an ordering term by the [expression], the [mode] (defaults to
/// ascending) and the [nulls].
OrderingTerm({
required this.expression,
this.mode = OrderingMode.asc,
this.nulls,
});
/// Creates an ordering term that sorts for ascending values
/// of [expression] and the [nulls].
factory OrderingTerm.asc(Expression expression, {NullsOrder? nulls}) {
return OrderingTerm(
expression: expression,
mode: OrderingMode.asc,
nulls: nulls,
);
}
/// Creates an ordering term that sorts for descending values of [expression].
factory OrderingTerm.desc(Expression expression) {
return OrderingTerm(expression: expression, mode: OrderingMode.desc);
/// Creates an ordering term that sorts for descending values
/// of [expression] and the [nulls].
factory OrderingTerm.desc(Expression expression, {NullsOrder? nulls}) {
return OrderingTerm(
expression: expression,
mode: OrderingMode.desc,
nulls: nulls,
);
}
/// Creates an ordering term to get a number of random rows
@ -47,7 +81,11 @@ class OrderingTerm extends Component {
void writeInto(GenerationContext context) {
expression.writeInto(context);
context.writeWhitespace();
context.buffer.write(_modeToString[mode]);
context.buffer.write(mode._mode);
if (nulls != null) {
context.writeWhitespace();
context.buffer.write(nulls?._order);
}
}
}

View File

@ -3,6 +3,8 @@ import 'dart:async';
/// Transforms a stream of lists into a stream of single elements, assuming
/// that each list is a singleton or empty.
StreamTransformer<List<T>, T?> singleElementsOrNull<T>() {
final originTrace = StackTrace.current;
return StreamTransformer.fromHandlers(handleData: (data, sink) {
T? result;
@ -11,7 +13,9 @@ StreamTransformer<List<T>, T?> singleElementsOrNull<T>() {
result = data.single;
}
} catch (e) {
throw StateError('Expected exactly one element, but got ${data.length}');
Error.throwWithStackTrace(
StateError('Expected exactly one element, but got ${data.length}'),
originTrace);
}
sink.add(result);
@ -21,13 +25,17 @@ StreamTransformer<List<T>, T?> singleElementsOrNull<T>() {
/// Transforms a stream of lists into a stream of single elements, assuming
/// that each list is a singleton.
StreamTransformer<List<T>, T> singleElements<T>() {
final originTrace = StackTrace.current;
return StreamTransformer.fromHandlers(handleData: (data, sink) {
T single;
try {
single = data.single;
} catch (e) {
throw StateError('Expected exactly one element, but got ${data.length}');
Error.throwWithStackTrace(
StateError('Expected exactly one element, but got ${data.length}'),
originTrace);
}
sink.add(single);

View File

@ -1,6 +1,6 @@
name: drift
description: Drift is a reactive library to store relational data in Dart and Flutter applications.
version: 2.0.2+1
version: 2.1.0
repository: https://github.com/simolus3/drift
homepage: https://drift.simonbinder.eu/
issue_tracker: https://github.com/simolus3/drift/issues
@ -33,3 +33,4 @@ dev_dependencies:
mockito: ^5.0.7
rxdart: ^0.27.0
shelf: ^1.3.0
stack_trace: ^1.10.0

View File

@ -0,0 +1,88 @@
import 'package:drift/drift.dart' hide isNull;
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import '../../generated/todos.dart';
import '../../test_utils/test_utils.dart';
void main() {
late TodoDb db;
late MockExecutor executor;
setUp(() {
executor = MockExecutor();
db = TodoDb(executor);
});
test('when nullsOrder is null it ignored', () async {
final query = db.select(db.users);
query.orderBy([(tbl) => OrderingTerm(expression: tbl.name)]);
await query.get();
verify(executor.runSelect(
'SELECT * FROM users ORDER BY name ASC;',
argThat(isEmpty),
));
});
test('nullsOrder is last', () async {
final query = db.select(db.users);
query.orderBy([
(tbl) => OrderingTerm(
expression: tbl.name,
nulls: NullsOrder.last,
),
]);
await query.get();
verify(executor.runSelect(
'SELECT * FROM users ORDER BY name ASC NULLS LAST;',
argThat(isEmpty),
));
});
test('nullsOrder is first', () async {
final query = db.select(db.users);
query.orderBy([
(tbl) => OrderingTerm(
expression: tbl.name,
nulls: NullsOrder.first,
),
]);
await query.get();
verify(executor.runSelect(
'SELECT * FROM users ORDER BY name ASC NULLS FIRST;',
argThat(isEmpty),
));
});
test('complex order by with different nullsOrder', () async {
final query = db.select(db.users);
query.orderBy([
(tbl) => OrderingTerm(
expression: tbl.name,
nulls: NullsOrder.first,
),
(tbl) => OrderingTerm(
expression: tbl.creationTime,
),
(tbl) => OrderingTerm(
expression: tbl.profilePicture,
nulls: NullsOrder.last,
),
]);
await query.get();
verify(executor.runSelect(
'SELECT * FROM users ORDER BY name ASC NULLS FIRST, creation_time ASC, profile_picture ASC NULLS LAST;',
argThat(isEmpty),
));
});
test('works with helper factories', () {
final table = db.users;
expect(OrderingTerm.asc(table.id), generates('id ASC'));
expect(OrderingTerm.asc(table.id, nulls: NullsOrder.last),
generates('id ASC NULLS LAST'));
expect(OrderingTerm.desc(table.id, nulls: NullsOrder.first),
generates('id DESC NULLS FIRST'));
});
}

View File

@ -1606,12 +1606,13 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}
Selectable<Config> readMultiple(List<String> var1,
{OrderBy Function(ConfigTable config) clause = _$moor$default$0}) {
{ReadMultiple$clause? clause}) {
var $arrayStartIndex = 1;
final expandedvar1 = $expandVar($arrayStartIndex, var1.length);
$arrayStartIndex += var1.length;
final generatedclause =
$write(clause(this.config), startIndex: $arrayStartIndex);
final generatedclause = $write(
clause?.call(this.config) ?? const OrderBy.nothing(),
startIndex: $arrayStartIndex);
$arrayStartIndex += generatedclause.amountOfVariables;
return customSelect(
'SELECT * FROM config WHERE config_key IN ($expandedvar1) ${generatedclause.sql}',
@ -1625,12 +1626,11 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}).asyncMap(config.mapFromRow);
}
Selectable<Config> readDynamic(
{Expression<bool> Function(ConfigTable config) predicate =
_$moor$default$1}) {
Selectable<Config> readDynamic({ReadDynamic$predicate? predicate}) {
var $arrayStartIndex = 1;
final generatedpredicate =
$write(predicate(this.config), startIndex: $arrayStartIndex);
final generatedpredicate = $write(
predicate?.call(this.config) ?? const CustomExpression('(TRUE)'),
startIndex: $arrayStartIndex);
$arrayStartIndex += generatedpredicate.amountOfVariables;
return customSelect('SELECT * FROM config WHERE ${generatedpredicate.sql}',
variables: [
@ -1643,10 +1643,11 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}
Selectable<String> typeConverterVar(SyncType? var1, List<SyncType?> var2,
{Expression<bool> Function(ConfigTable config) pred = _$moor$default$2}) {
{TypeConverterVar$pred? pred}) {
var $arrayStartIndex = 2;
final generatedpred =
$write(pred(this.config), startIndex: $arrayStartIndex);
final generatedpred = $write(
pred?.call(this.config) ?? const CustomExpression('(TRUE)'),
startIndex: $arrayStartIndex);
$arrayStartIndex += generatedpred.amountOfVariables;
final expandedvar2 = $expandVar($arrayStartIndex, var2.length);
$arrayStartIndex += var2.length;
@ -1694,9 +1695,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
});
}
Selectable<MultipleResult> multiple(
{required Expression<bool> Function(WithDefaults d, WithConstraints c)
predicate}) {
Selectable<MultipleResult> multiple({required Multiple$predicate predicate}) {
var $arrayStartIndex = 1;
final generatedpredicate = $write(
predicate(
@ -1734,8 +1733,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}).asyncMap(email.mapFromRow);
}
Selectable<ReadRowIdResult> readRowId(
{required Expression<int> Function(ConfigTable config) expr}) {
Selectable<ReadRowIdResult> readRowId({required ReadRowId$expr expr}) {
var $arrayStartIndex = 1;
final generatedexpr =
$write(expr(this.config), startIndex: $arrayStartIndex);
@ -1865,11 +1863,9 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
const DriftDatabaseOptions(storeDateTimeAsText: true);
}
OrderBy _$moor$default$0(ConfigTable _) => const OrderBy.nothing();
Expression<bool> _$moor$default$1(ConfigTable _) =>
const CustomExpression('(TRUE)');
Expression<bool> _$moor$default$2(ConfigTable _) =>
const CustomExpression('(TRUE)');
typedef ReadMultiple$clause = OrderBy Function(ConfigTable config);
typedef ReadDynamic$predicate = Expression<bool> Function(ConfigTable config);
typedef TypeConverterVar$pred = Expression<bool> Function(ConfigTable config);
class JsonResult extends CustomResultSet {
final String key;
@ -1927,6 +1923,9 @@ class MultipleResult extends CustomResultSet {
}
}
typedef Multiple$predicate = Expression<bool> Function(
WithDefaults d, WithConstraints c);
class ReadRowIdResult extends CustomResultSet {
final int rowid;
final String configKey;
@ -1966,6 +1965,8 @@ class ReadRowIdResult extends CustomResultSet {
}
}
typedef ReadRowId$expr = Expression<int> Function(ConfigTable config);
class NestedResult extends CustomResultSet {
final WithDefault defaults;
final List<WithConstraint> nestedQuery0;

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:drift/src/utils/single_transformer.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:test/test.dart';
void main() {
@ -44,6 +45,44 @@ void main() {
final stream = Stream.value([]);
expect(stream.transform(singleElementsOrNull()), emits(isNull));
});
test('stack traces reflect where the transformer was created', () {
final controller = StreamController<List<int>>();
final stream = controller.stream.transform(singleElements());
final error = isStateError.having(
(e) => e.stackTrace,
'stackTrace',
// Make sure that the predicate points to where the transformation was
// applied instead of just containing asynchronous gaps and drift-internal
// frames.
predicate((trace) {
final parsed = Trace.from(trace as StackTrace);
return parsed.frames.any(
(f) =>
f.uri.path.contains('single_transformer_test.dart') &&
f.line == 51,
);
}),
);
expectLater(
stream,
emitsInOrder([
1,
emitsError(error),
2,
emitsDone,
]),
);
controller
..add([1])
..add([2, 3])
..add([2])
..close();
}, testOn: 'vm');
}
Matcher _stateErrorWithTrace =

View File

@ -1,3 +1,15 @@
## 2.1.0
- Analysis support `fts5` tables with external content tables.
- Analysis support for the `rtree` module.
- Prepare for an upcoming breaking analyzer change around how classes are mapped
to elements.
## 2.0.2
- Generate public typedefs for the signatures of `scoped_dart_components`,
making it easier to re-use them for own methods.
## 2.0.1
- Recognize options for an applied `not_shared` builder when exporting schemas.

View File

@ -4,6 +4,7 @@ import 'package:drift_dev/src/analyzer/errors.dart';
import 'package:drift_dev/src/analyzer/runner/results.dart';
import 'package:drift_dev/src/analyzer/runner/steps.dart';
import 'package:drift_dev/src/analyzer/sql_queries/query_analyzer.dart';
import 'package:source_span/source_span.dart';
import 'package:sqlparser/sqlparser.dart';
import 'package:sqlparser/utils/find_referenced_tables.dart';
@ -39,6 +40,11 @@ class EntityHandler extends BaseAnalyzer {
final node =
_handleMoorDeclaration<DriftTableDeclaration>(entity, _tables);
_lint(node, entity.sqlName);
final parserTable = entity.parserTable;
if (parserTable is Fts5Table) {
_checkFts5References(entity, parserTable);
}
} else if (entity is MoorTrigger) {
entity.clearResolvedReferences();
@ -73,6 +79,63 @@ class EntityHandler extends BaseAnalyzer {
lintContext(context, displayName);
}
void _checkFts5References(DriftTable drift, Fts5Table rawTable) {
FileSpan? span;
final declaration = drift.declaration;
if (declaration is DriftTableDeclaration) {
span = declaration.node.tableNameToken?.span;
}
final contentTable = rawTable.contentTable;
final contentRowId = rawTable.contentRowId;
if (contentTable != null && contentTable.isNotEmpty) {
final referenced = _resolveTableOrView(contentTable);
if (referenced != null) {
drift.references.add(referenced);
// Check that fts5 columns also exist in the reference table.
for (final column in rawTable.resultColumns) {
final name = column.name.toLowerCase();
final foundColumn =
referenced.columns.any((c) => c.name.name.toLowerCase() == name);
if (!foundColumn) {
step.reportError(ErrorInDriftFile(
severity: Severity.error,
span: span,
message: 'The content table has no column `${column.name}`, but '
'this fts5 table references it',
));
}
}
// If a custom rowid is set, check that it exists
if (contentRowId != null && !aliasesForRowId.contains(contentRowId)) {
final name = contentRowId.toLowerCase();
final foundColumn = referenced.columns
.firstWhereOrNull((c) => c.name.name.toLowerCase() == name);
if (foundColumn == null) {
step.reportError(ErrorInDriftFile(
severity: Severity.error,
span: span,
message: 'The content table has no column `$contentRowId`, but '
'this fts5 table is declared to use it as a row id',
));
}
}
} else {
step.reportError(ErrorInDriftFile(
severity: Severity.error,
span: span,
message: 'Content table `$contentTable` could not be found.',
));
}
}
}
Iterable<DriftTable> _findTables(AstNode node) {
return findReferences(node, includeViews: false).cast();
}
@ -105,6 +168,18 @@ class EntityHandler extends BaseAnalyzer {
MoorIndex? _inducedIndex(CreateIndexStatement stmt) {
return _indexes[stmt];
}
DriftTable? _resolveTable(String name) {
final lower = name.toLowerCase();
return tables.firstWhereOrNull((t) => t.sqlName.toLowerCase() == lower);
}
DriftEntityWithResultSet? _resolveTableOrView(String name) {
final lower = name.toLowerCase();
return _resolveTable(name) ??
views.firstWhereOrNull((v) => v.name.toLowerCase() == lower);
}
}
class _ReferenceResolvingVisitor extends RecursiveVisitor<void, void> {
@ -113,8 +188,7 @@ class _ReferenceResolvingVisitor extends RecursiveVisitor<void, void> {
_ReferenceResolvingVisitor(this.handler);
DriftTable? _resolveTable(TableReference reference) {
return handler.tables
.firstWhereOrNull((t) => t.sqlName == reference.tableName);
return handler._resolveTable(reference.tableName);
}
@override

View File

@ -23,7 +23,7 @@ Future<FoundDartClass?> findDartClass(
}
final foundElement = library.exportNamespace.get(identifier);
if (foundElement is ClassElement) {
if (foundElement is InterfaceElement) {
return FoundDartClass(foundElement, null);
} else if (foundElement is TypeAliasElement) {
final innerType = foundElement.aliasedType;

View File

@ -78,7 +78,7 @@ class ErrorInDartCode extends DriftError {
}
class ErrorInDriftFile extends DriftError {
final FileSpan span;
final FileSpan? span;
ErrorInDriftFile(
{required this.span,
@ -108,7 +108,12 @@ class ErrorInDriftFile extends DriftError {
@override
void writeDescription(LogFunction log) {
log(span.message(message, color: isError));
final errorSpan = span;
if (errorSpan != null) {
log(errorSpan.message(message, color: isError));
} else {
log(message);
}
}
}

View File

@ -22,13 +22,13 @@ class HelperLibrary {
/// Returns `null` if [type] is not a subtype of `TypeConverter`.
InterfaceType? asTypeConverter(DartType type) {
final converter =
helperLibrary.exportNamespace.get('TypeConverter') as ClassElement;
helperLibrary.exportNamespace.get('TypeConverter') as InterfaceElement;
return type.asInstanceOf(converter);
}
bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) {
final jsonMixin =
helperLibrary.exportNamespace.get('JsonTypeConverter') as ClassElement;
final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter')
as InterfaceElement;
final jsonConverterType = jsonMixin.instantiate(
typeArguments: [
context.typeProvider.dynamicType,

View File

@ -275,4 +275,8 @@ enum SqlModule {
///
/// [math funs]: https://www.sqlite.org/lang_mathfunc.html
math,
/// Enables support for the rtree module and its functions when parsing sql
/// queries.
rtree,
}

View File

@ -140,6 +140,7 @@ const _$SqlModuleEnumMap = {
SqlModule.fts5: 'fts5',
SqlModule.moor_ffi: 'moor_ffi',
SqlModule.math: 'math',
SqlModule.rtree: 'rtree',
};
DialectOptions _$DialectOptionsFromJson(Map json) => $checkedCreate(

View File

@ -122,15 +122,18 @@ class ParseDartStep extends Step {
Future<List<DriftTable>> parseTables(
Iterable<DartType> types, Element initializedBy) {
return Future.wait(types.map((type) {
if (!_tableTypeChecker.isAssignableFromType(type)) {
final element = type is InterfaceType ? type.element2 : null;
if (!_tableTypeChecker.isAssignableFromType(type) ||
element is! ClassElement) {
reportError(ErrorInDartCode(
severity: Severity.criticalError,
message: 'The type $type is not a moor table',
message: 'The type $type is not a drift table class.',
affectedElement: initializedBy,
));
return Future.value(null);
} else {
return _parseTable((type as InterfaceType).element2 as ClassElement);
return _parseTable(element);
}
})).then((list) {
// only keep tables that were resolved successfully
@ -145,16 +148,18 @@ class ParseDartStep extends Step {
Future<List<MoorView>> parseViews(Iterable<DartType> types,
Element initializedBy, List<DriftTable> tables) {
return Future.wait(types.map((type) {
if (!_viewTypeChecker.isAssignableFromType(type)) {
final element = type is InterfaceType ? type.element2 : null;
if (!_viewTypeChecker.isAssignableFromType(type) ||
element is! ClassElement) {
reportError(ErrorInDartCode(
severity: Severity.criticalError,
message: 'The type $type is not a drift view',
message: 'The type $type is not a drift view class.',
affectedElement: initializedBy,
));
return Future.value(null);
} else {
return _parseView(
(type as InterfaceType).element2 as ClassElement, tables);
return _parseView(element, tables);
}
})).then((list) {
// only keep tables that were resolved successfully

View File

@ -45,6 +45,7 @@ class MoorSession {
if (options.hasModule(SqlModule.json1)) const Json1Extension(),
if (options.hasModule(SqlModule.moor_ffi)) const MoorFfiExtension(),
if (options.hasModule(SqlModule.math)) const BuiltInMathExtension(),
if (options.hasModule(SqlModule.rtree)) const RTreeExtension(),
],
version: options.sqliteVersion,
);

View File

@ -42,11 +42,13 @@ class ErrorService {
Location _findLocationForError(DriftError error, String path) {
if (error is ErrorInDriftFile) {
final span = error.span;
final start = span.start;
final end = span.end;
return Location(
path, start.offset, span.length, start.line + 1, start.column + 1,
endLine: end.line + 1, endColumn: end.column + 1);
if (span != null) {
final start = span.start;
final end = span.end;
return Location(
path, start.offset, span.length, start.line + 1, start.column + 1,
endLine: end.line + 1, endColumn: end.column + 1);
}
}
return Location(path, 0, 0, 0, 0);

View File

@ -37,6 +37,9 @@ abstract class DriftEntityWithResultSet extends DriftSchemaEntity {
@Deprecated('Use dartTypeCode instead')
String get dartTypeName;
/// The (unescaped) name of this table when stored in the database
String get sqlName;
/// The type name of the Dart row class for this result set.
///
/// This may contain generics.

View File

@ -827,6 +827,12 @@ class FoundDartPlaceholder extends FoundElement {
type is ExpressionDartPlaceholderType &&
(type as ExpressionDartPlaceholderType).defaultValue != null;
bool get hasDefaultOrImplicitFallback =>
hasDefault ||
(type is SimpleDartPlaceholderType &&
(type as SimpleDartPlaceholderType).kind ==
SimpleDartPlaceholderKind.orderBy);
FoundDartPlaceholder(this.type, this.name, this.availableResultSets);
@override

View File

@ -44,7 +44,7 @@ class DriftTable extends DriftEntityWithResultSet {
@override
final List<DriftColumn> columns;
/// The (unescaped) name of this table when stored in the database
@override
final String sqlName;
/// The name for the data class associated with this table
@ -120,7 +120,7 @@ class DriftTable extends DriftEntityWithResultSet {
final List<String>? overrideTableConstraints;
@override
final Set<DriftTable> references = {};
final Set<DriftEntityWithResultSet> references = {};
/// Returns whether this table was created from a `CREATE VIRTUAL TABLE`
/// statement in a moor file

View File

@ -21,6 +21,9 @@ class MoorView extends DriftEntityWithResultSet {
final String name;
@override
String get sqlName => name;
@override
List<DriftSchemaEntity> references = [];

View File

@ -4,6 +4,7 @@ import 'package:drift_dev/src/analyzer/sql_queries/explicit_alias_transformer.da
import 'package:drift_dev/src/analyzer/sql_queries/nested_queries.dart';
import 'package:drift_dev/src/utils/string_escaper.dart';
import 'package:drift_dev/writer.dart';
import 'package:recase/recase.dart';
import 'package:sqlparser/sqlparser.dart' hide ResultColumn;
import 'sql_writer.dart';
@ -254,20 +255,25 @@ class QueryWriter {
void _writeParameters(SqlQuery query) {
final namedElements = <FoundElement>[];
String scopedTypeName(FoundDartPlaceholder element) {
return '${ReCase(query.name).pascalCase}\$${ReCase(element.name).camelCase}';
}
String typeFor(FoundElement element) {
var type = element.dartTypeCode();
return element.dartTypeCode();
}
if (element is FoundDartPlaceholder &&
element.writeAsScopedFunction(options)) {
// Generate a function providing result sets that are in scope as args
String writeScopedTypeFor(FoundDartPlaceholder element) {
final root = scope.root;
final type = typeFor(element);
final scopedType = scopedTypeName(element);
final args = element.availableResultSets
.map((e) => '${e.argumentType} ${e.name}')
.join(', ');
type = '$type Function($args)';
}
final args = element.availableResultSets
.map((e) => '${e.argumentType} ${e.name}')
.join(', ');
root.leaf().write('typedef $scopedType = $type Function($args);');
return type;
return scopedType;
}
var needsComma = false;
@ -285,7 +291,11 @@ class QueryWriter {
} else {
if (needsComma) _buffer.write(', ');
final type = typeFor(element);
var type = typeFor(element);
if (element is FoundDartPlaceholder &&
element.writeAsScopedFunction(options)) {
type = writeScopedTypeFor(element);
}
_buffer.write('$type ${element.dartParameterName}');
needsComma = true;
}
@ -302,62 +312,27 @@ class QueryWriter {
needsComma = true;
String? defaultCode;
var isNullable = false;
var type = typeFor(optional);
if (optional is FoundDartPlaceholder) {
final kind = optional.type;
if (kind is ExpressionDartPlaceholderType &&
kind.defaultValue != null) {
// Wrap the default expression in parentheses to avoid issues with
// the surrounding precedence in SQL.
final sql = SqlWriter(scope.options)
.writeNodeIntoStringLiteral(Parentheses(kind.defaultValue!));
defaultCode = 'const CustomExpression($sql)';
} else if (kind is SimpleDartPlaceholderType &&
kind.kind == SimpleDartPlaceholderKind.orderBy) {
defaultCode = 'const OrderBy.nothing()';
}
// If optional Dart placeholders are written as functions, they are
// generated as nullable parameters. The default is handled with a
// `??` in the method's body.
if (optional.writeAsScopedFunction(options)) {
isNullable = optional.hasDefaultOrImplicitFallback;
type = writeScopedTypeFor(optional);
// If the parameter is converted to a scoped function, we also need to
// generate a scoped function as a default value. Since defaults have
// to be constants, we generate a top-level function which is then
// used as a tear-off.
if (optional.writeAsScopedFunction(options) && defaultCode != null) {
final root = scope.root;
final counter = root.counter++;
// ignore: prefer_interpolation_to_compose_strings
final functionName = r'_$moor$default$' + counter.toString();
final buffer = root.leaf()
..write(optional.dartTypeCode(scope.generationOptions))
..write(' ')
..write(functionName)
..write('(');
var i = 0;
for (final arg in optional.availableResultSets) {
if (i != 0) buffer.write(', ');
buffer
..write(arg.argumentType)
..write(' ')
..write('_' * (i + 1));
i++;
if (isNullable) {
type += '?';
}
buffer
..write(') => ')
..write(defaultCode)
..write(';');
// With the function being written, the default code is just a tear-
// off of that function
defaultCode = functionName;
} else {
defaultCode = _defaultForDartPlaceholder(optional, scope);
}
}
final type = typeFor(optional);
// No default value, this element is required if it's not nullable
var isMarkedAsRequired = false;
var isNullable = false;
if (optional is FoundVariable) {
isMarkedAsRequired = optional.isRequired;
isNullable = optional.nullableInDart;
@ -382,7 +357,7 @@ class QueryWriter {
}
void _writeExpandedDeclarations(SqlQuery query) {
_ExpandedDeclarationWriter(query, options, _buffer)
_ExpandedDeclarationWriter(query, options, scope, _buffer)
.writeExpandedDeclarations();
}
@ -441,13 +416,15 @@ String _converter(UsedTypeConverter converter) {
class _ExpandedDeclarationWriter {
final SqlQuery query;
final DriftOptions options;
final Scope _scope;
final StringBuffer _buffer;
bool indexCounterWasDeclared = false;
bool needsIndexCounter = false;
int highestIndexBeforeArray = 0;
_ExpandedDeclarationWriter(this.query, this.options, this._buffer);
_ExpandedDeclarationWriter(
this.query, this.options, this._scope, this._buffer);
void writeExpandedDeclarations() {
// When the SQL query is written to a Dart string, we give each variable an
@ -532,7 +509,17 @@ class _ExpandedDeclarationWriter {
return table;
}
}).join(', ');
return '${element.dartParameterName}($args)';
final defaultValue = _defaultForDartPlaceholder(element, _scope);
if (defaultValue != null) {
// Optional elements written as a function are generated as nullable
// parameters. We need to emit the default if the actual value is
// null at runtime.
return '${element.dartParameterName}?.call($args) ?? $defaultValue';
} else {
return '${element.dartParameterName}($args)';
}
} else {
// We can just use the parameter directly
return element.dartParameterName;
@ -694,3 +681,21 @@ class _ExpandedVariableWriter {
_buffer.write('...${placeholderContextName(element)}.introducedVariables');
}
}
String? _defaultForDartPlaceholder(
FoundDartPlaceholder placeholder, Scope scope) {
final kind = placeholder.type;
if (kind is ExpressionDartPlaceholderType && kind.defaultValue != null) {
// Wrap the default expression in parentheses to avoid issues with
// the surrounding precedence in SQL.
final sql = SqlWriter(scope.options)
.writeNodeIntoStringLiteral(Parentheses(kind.defaultValue!));
return 'const CustomExpression($sql)';
} else if (kind is SimpleDartPlaceholderType &&
kind.kind == SimpleDartPlaceholderKind.orderBy) {
return 'const OrderBy.nothing()';
} else {
assert(!placeholder.hasDefaultOrImplicitFallback);
return null;
}
}

View File

@ -1,6 +1,6 @@
name: drift_dev
description: Dev-dependency for users of drift. Contains a the generator and development tools.
version: 2.0.1
version: 2.1.0
repository: https://github.com/simolus3/drift
homepage: https://drift.simonbinder.eu/
issue_tracker: https://github.com/simolus3/drift/issues
@ -25,9 +25,9 @@ dependencies:
io: ^1.0.3
# Drift-specific analysis and apis
drift: '>=2.0.0 <2.1.0'
drift: '>=2.0.0 <2.2.0'
sqlite3: '>=0.1.6 <2.0.0'
sqlparser: ^0.23.0
sqlparser: ^0.23.2
# Dart analysis
analyzer: "^4.5.0"

View File

@ -118,7 +118,7 @@ void main() {
'message',
allOf(contains('NotAnEnum'), contains('Not an enum')),
)
.having((e) => e.span.text, 'span', 'ENUM(NotAnEnum)'),
.having((e) => e.span?.text, 'span', 'ENUM(NotAnEnum)'),
),
);
});

View File

@ -43,7 +43,7 @@ void main() {
'message',
contains('Is it a part file?'),
)
.having((e) => e.span.text, 'span.text', "import 'tables.dart';"),
.having((e) => e.span?.text, 'span.text', "import 'tables.dart';"),
);
});
}

View File

@ -0,0 +1,92 @@
import 'package:drift_dev/src/analyzer/errors.dart';
import 'package:drift_dev/src/analyzer/options.dart';
import 'package:test/test.dart';
import '../utils.dart';
const _options = DriftOptions.defaults(modules: [SqlModule.fts5]);
void main() {
group('reports error', () {
test('for missing content table', () async {
final state = TestState.withContent({
'a|lib/main.drift': '''
CREATE VIRTUAL TABLE fts USING fts5(a, c, content=tbl);
''',
}, options: _options);
addTearDown(state.close);
final result = await state.analyze('package:a/main.drift');
expect(result.errors.errors, [
const TypeMatcher<ErrorInDriftFile>().having(
(e) => e.message,
'message',
contains('Content table `tbl` could not be found'),
),
]);
});
test('for invalid rowid of content table', () async {
final state = TestState.withContent({
'a|lib/main.drift': '''
CREATE TABLE tbl (a, b, c, my_pk INTEGER PRIMARY KEY);
CREATE VIRTUAL TABLE fts USING fts5(a, c, content=tbl, content_rowid=d);
''',
}, options: _options);
addTearDown(state.close);
final result = await state.analyze('package:a/main.drift');
expect(result.errors.errors, [
const TypeMatcher<ErrorInDriftFile>().having(
(e) => e.message,
'message',
contains(
'no column `d`, but this fts5 table is declared to use it as a row '
'id',
),
),
]);
});
test('when referencing an unknown column', () async {
final state = TestState.withContent({
'a|lib/main.drift': '''
CREATE TABLE tbl (a, b, c, d INTEGER PRIMARY KEY);
CREATE VIRTUAL TABLE fts USING fts5(e, c, content=tbl, content_rowid=d);
''',
}, options: _options);
addTearDown(state.close);
final result = await state.analyze('package:a/main.drift');
expect(result.errors.errors, [
const TypeMatcher<ErrorInDriftFile>().having(
(e) => e.message,
'message',
contains('no column `e`, but this fts5 table references it'),
),
]);
});
});
test('finds referenced table', () async {
final state = TestState.withContent({
'a|lib/main.drift': '''
CREATE TABLE tbl (a, b, c, d INTEGER PRIMARY KEY);
CREATE VIRTUAL TABLE fts USING fts5(a, c, content=tbl, content_rowid=d);
CREATE VIRTUAL TABLE fts2 USING fts5(a, c, content=tbl, content_rowid=rowid);
''',
}, options: _options);
addTearDown(state.close);
final result = await state.analyze('package:a/main.drift');
expect(result.errors.errors, isEmpty);
final tables = result.currentResult!.declaredTables.toList();
expect(tables, hasLength(3));
expect(tables[1].references, contains(tables[0]));
expect(tables[2].references, contains(tables[0]));
});
}

View File

@ -117,7 +117,7 @@ wrongArgs: SELECT sin(oid, foo) FROM numbers;
final fileB = await state.analyze('package:foo/b.moor');
expect(fileB.errors.errors, [
const TypeMatcher<ErrorInDriftFile>()
.having((e) => e.span.text, 'span.text', 'sin(oid, foo)')
.having((e) => e.span?.text, 'span.text', 'sin(oid, foo)')
]);
});
}

View File

@ -3,6 +3,7 @@
This collection of examples demonstrates how to use some advanced drift features.
- `app`: A cross-platform Flutter app built with recommended drift options.
- `encryption`: A very simple Flutter app running an encrypted drift database.
- `flutter_web_worker_example`: Asynchronously run a drift database through a web worker with Fluter.
- `migrations_example`: Example showing to how to generate test utilities to verify schema migration.
- `web_worker_-_example`: Asynchronously run a drift database through a web worker, without Flutter.

47
examples/encryption/.gitignore vendored Normal file
View File

@ -0,0 +1,47 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View File

@ -0,0 +1,42 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: f1875d570e39de09040c8f79aa13cc56baab8db1
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: android
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: ios
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: linux
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: macos
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: windows
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@ -0,0 +1,8 @@
# drift_encryption_sample
This simple example demonstrates how to use drift with an encrypted database,
based on `sqlcipher_flutter_libs`.
At the moment, this app supports Android, iOS and macOS.
To run it, simply use `flutter run`.

View File

@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

13
examples/encryption/android/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,71 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.drift_encryption_sample"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.drift_encryption_sample">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.drift_encryption_sample">
<application
android:label="drift_encryption_sample"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -0,0 +1,6 @@
package com.example.drift_encryption_sample
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.drift_encryption_sample">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,31 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

View File

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

34
examples/encryption/ios/.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
</dict>
</plist>

View File

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

View File

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

View File

@ -0,0 +1,481 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.driftEncryptionSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.driftEncryptionSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.driftEncryptionSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</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,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

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,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Drift Encryption Sample</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>drift_encryption_sample</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View File

@ -0,0 +1,64 @@
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
part 'database.g.dart';
// This database is kep simple on purpose, this example only demonstrates how to
// use drift with an encrypted database.
// For advanced drift features, see the other examples in this project.
const _encryptionPassword = 'drift.example.unsafe_password';
class Notes extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get content => text()();
}
@DriftDatabase(tables: [Notes])
class MyEncryptedDatabase extends _$MyEncryptedDatabase {
MyEncryptedDatabase() : super(_openDatabase());
@override
int get schemaVersion => 1;
@override
MigrationStrategy get migration {
return MigrationStrategy(
beforeOpen: (details) async {},
);
}
}
QueryExecutor _openDatabase() {
return LazyDatabase(() async {
final path = await getApplicationDocumentsDirectory();
return NativeDatabase(
File(p.join(path.path, 'app.db.enc')),
setup: (db) {
// Check that we're actually running with SQLCipher by quering the
// cipher_version pragma.
final result = db.select('pragma cipher_version');
if (result.isEmpty) {
throw UnsupportedError(
'This database needs to run with SQLCipher, but that library is '
'not available!',
);
}
// Then, apply the key to encrypt the database. Unfortunately, this
// pragma doesn't seem to support prepared statements so we inline the
// key.
final escapedKey = _encryptionPassword.replaceAll("'", "''");
db.execute("pragma key = '$escapedKey'");
// Test that the key is correct by selecting from a table
db.execute('select count(*) from sqlite_master');
},
);
});
}

View File

@ -0,0 +1,184 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'database.dart';
// **************************************************************************
// DriftDatabaseGenerator
// **************************************************************************
// ignore_for_file: type=lint
class Note extends DataClass implements Insertable<Note> {
final int id;
final String content;
const Note({required this.id, required this.content});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['id'] = Variable<int>(id);
map['content'] = Variable<String>(content);
return map;
}
NotesCompanion toCompanion(bool nullToAbsent) {
return NotesCompanion(
id: Value(id),
content: Value(content),
);
}
factory Note.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return Note(
id: serializer.fromJson<int>(json['id']),
content: serializer.fromJson<String>(json['content']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
'content': serializer.toJson<String>(content),
};
}
Note copyWith({int? id, String? content}) => Note(
id: id ?? this.id,
content: content ?? this.content,
);
@override
String toString() {
return (StringBuffer('Note(')
..write('id: $id, ')
..write('content: $content')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(id, content);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is Note && other.id == this.id && other.content == this.content);
}
class NotesCompanion extends UpdateCompanion<Note> {
final Value<int> id;
final Value<String> content;
const NotesCompanion({
this.id = const Value.absent(),
this.content = const Value.absent(),
});
NotesCompanion.insert({
this.id = const Value.absent(),
required String content,
}) : content = Value(content);
static Insertable<Note> custom({
Expression<int>? id,
Expression<String>? content,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
if (content != null) 'content': content,
});
}
NotesCompanion copyWith({Value<int>? id, Value<String>? content}) {
return NotesCompanion(
id: id ?? this.id,
content: content ?? this.content,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (id.present) {
map['id'] = Variable<int>(id.value);
}
if (content.present) {
map['content'] = Variable<String>(content.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('NotesCompanion(')
..write('id: $id, ')
..write('content: $content')
..write(')'))
.toString();
}
}
class $NotesTable extends Notes with TableInfo<$NotesTable, Note> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$NotesTable(this.attachedDatabase, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
@override
late final GeneratedColumn<int> id = GeneratedColumn<int>(
'id', aliasedName, false,
type: DriftSqlType.int,
requiredDuringInsert: false,
defaultConstraints: 'PRIMARY KEY AUTOINCREMENT');
final VerificationMeta _contentMeta = const VerificationMeta('content');
@override
late final GeneratedColumn<String> content = GeneratedColumn<String>(
'content', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
@override
List<GeneratedColumn> get $columns => [id, content];
@override
String get aliasedName => _alias ?? 'notes';
@override
String get actualTableName => 'notes';
@override
VerificationContext validateIntegrity(Insertable<Note> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
}
if (data.containsKey('content')) {
context.handle(_contentMeta,
content.isAcceptableOrUnknown(data['content']!, _contentMeta));
} else if (isInserting) {
context.missing(_contentMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Note map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return Note(
id: attachedDatabase.options.types
.read(DriftSqlType.int, data['${effectivePrefix}id'])!,
content: attachedDatabase.options.types
.read(DriftSqlType.string, data['${effectivePrefix}content'])!,
);
}
@override
$NotesTable createAlias(String alias) {
return $NotesTable(attachedDatabase, alias);
}
}
abstract class _$MyEncryptedDatabase extends GeneratedDatabase {
_$MyEncryptedDatabase(QueryExecutor e) : super(e);
late final $NotesTable notes = $NotesTable(this);
@override
Iterable<TableInfo<Table, dynamic>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [notes];
}

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