Initial commit
This commit is contained in:
commit
5cc0bba09a
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
30
.metadata
Normal file
30
.metadata
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
- platform: android
|
||||||
|
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# okane
|
||||||
|
|
||||||
|
A new Flutter project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
28
analysis_options.yaml
Normal file
28
analysis_options.yaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
14
android/.gitignore
vendored
Normal file
14
android/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/to/reference-keystore
|
||||||
|
key.properties
|
||||||
|
**/*.keystore
|
||||||
|
**/*.jks
|
44
android/app/build.gradle.kts
Normal file
44
android/app/build.gradle.kts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("kotlin-android")
|
||||||
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
|
id("dev.flutter.flutter-gradle-plugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.example.okane"
|
||||||
|
compileSdk = flutter.compileSdkVersion
|
||||||
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
|
applicationId = "com.example.okane"
|
||||||
|
// You can update the following values to match your application needs.
|
||||||
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
|
minSdk = flutter.minSdkVersion
|
||||||
|
targetSdk = flutter.targetSdkVersion
|
||||||
|
versionCode = flutter.versionCode
|
||||||
|
versionName = flutter.versionName
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
// TODO: Add your own signing config for the release build.
|
||||||
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flutter {
|
||||||
|
source = "../.."
|
||||||
|
}
|
7
android/app/src/debug/AndroidManifest.xml
Normal file
7
android/app/src/debug/AndroidManifest.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
45
android/app/src/main/AndroidManifest.xml
Normal file
45
android/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<application
|
||||||
|
android:label="okane"
|
||||||
|
android:name="${applicationName}"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
the Android process has started. This theme is visible to the user
|
||||||
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
to determine the Window background behind the Flutter UI. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
|
android:resource="@style/NormalTheme"
|
||||||
|
/>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- Don't delete the meta-data below.
|
||||||
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutterEmbedding"
|
||||||
|
android:value="2" />
|
||||||
|
</application>
|
||||||
|
<!-- Required to query activities that can process text, see:
|
||||||
|
https://developer.android.com/training/package-visibility and
|
||||||
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
|
||||||
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
|
<data android:mimeType="text/plain"/>
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
</manifest>
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.okane
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity : FlutterActivity()
|
12
android/app/src/main/res/drawable-v21/launch_background.xml
Normal file
12
android/app/src/main/res/drawable-v21/launch_background.xml
Normal 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>
|
12
android/app/src/main/res/drawable/launch_background.xml
Normal file
12
android/app/src/main/res/drawable/launch_background.xml
Normal 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>
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 544 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 442 B |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 721 B |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
18
android/app/src/main/res/values-night/styles.xml
Normal file
18
android/app/src/main/res/values-night/styles.xml
Normal 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>
|
18
android/app/src/main/res/values/styles.xml
Normal file
18
android/app/src/main/res/values/styles.xml
Normal 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>
|
7
android/app/src/profile/AndroidManifest.xml
Normal file
7
android/app/src/profile/AndroidManifest.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
21
android/build.gradle.kts
Normal file
21
android/build.gradle.kts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
|
||||||
|
rootProject.layout.buildDirectory.value(newBuildDir)
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||||
|
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||||
|
}
|
||||||
|
subprojects {
|
||||||
|
project.evaluationDependsOn(":app")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<Delete>("clean") {
|
||||||
|
delete(rootProject.layout.buildDirectory)
|
||||||
|
}
|
3
android/gradle.properties
Normal file
3
android/gradle.properties
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
25
android/settings.gradle.kts
Normal file
25
android/settings.gradle.kts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
pluginManagement {
|
||||||
|
val flutterSdkPath = run {
|
||||||
|
val properties = java.util.Properties()
|
||||||
|
file("local.properties").inputStream().use { properties.load(it) }
|
||||||
|
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||||
|
flutterSdkPath
|
||||||
|
}
|
||||||
|
|
||||||
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
|
id("com.android.application") version "8.7.0" apply false
|
||||||
|
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
include(":app")
|
10
lib/database/collections/account.dart
Normal file
10
lib/database/collections/account.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
|
part 'account.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class Account {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
String? name;
|
||||||
|
}
|
469
lib/database/collections/account.g.dart
Normal file
469
lib/database/collections/account.g.dart
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'account.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetAccountCollection on Isar {
|
||||||
|
IsarCollection<Account> get accounts => this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccountSchema = CollectionSchema(
|
||||||
|
name: r'Account',
|
||||||
|
id: -6646797162501847804,
|
||||||
|
properties: {
|
||||||
|
r'name': PropertySchema(id: 0, name: r'name', type: IsarType.string),
|
||||||
|
},
|
||||||
|
estimateSize: _accountEstimateSize,
|
||||||
|
serialize: _accountSerialize,
|
||||||
|
deserialize: _accountDeserialize,
|
||||||
|
deserializeProp: _accountDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _accountGetId,
|
||||||
|
getLinks: _accountGetLinks,
|
||||||
|
attach: _accountAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _accountEstimateSize(
|
||||||
|
Account object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
{
|
||||||
|
final value = object.name;
|
||||||
|
if (value != null) {
|
||||||
|
bytesCount += 3 + value.length * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _accountSerialize(
|
||||||
|
Account object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeString(offsets[0], object.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Account _accountDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = Account();
|
||||||
|
object.id = id;
|
||||||
|
object.name = reader.readStringOrNull(offsets[0]);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _accountDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readStringOrNull(offset)) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _accountGetId(Account object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _accountGetLinks(Account object) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _accountAttach(IsarCollection<dynamic> col, Id id, Account object) {
|
||||||
|
object.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryWhereSort on QueryBuilder<Account, Account, QWhere> {
|
||||||
|
QueryBuilder<Account, Account, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryWhere on QueryBuilder<Account, Account, QWhereClause> {
|
||||||
|
QueryBuilder<Account, Account, QAfterWhereClause> idEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterWhereClause> idNotEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterWhereClause> idGreaterThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterWhereClause> idLessThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterWhereClause> idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryFilter
|
||||||
|
on QueryBuilder<Account, Account, QFilterCondition> {
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> idEqualTo(Id value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> idGreaterThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> idLessThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNull(property: r'name'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameIsNotNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNotNull(property: r'name'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameEqualTo(
|
||||||
|
String? value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameGreaterThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameLessThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameBetween(
|
||||||
|
String? lower,
|
||||||
|
String? upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'name',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameStartsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameEndsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameContains(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameMatches(
|
||||||
|
String pattern, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'name',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterFilterCondition> nameIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryObject
|
||||||
|
on QueryBuilder<Account, Account, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension AccountQueryLinks
|
||||||
|
on QueryBuilder<Account, Account, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension AccountQuerySortBy on QueryBuilder<Account, Account, QSortBy> {
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> sortByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> sortByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQuerySortThenBy
|
||||||
|
on QueryBuilder<Account, Account, QSortThenBy> {
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> thenByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, Account, QAfterSortBy> thenByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryWhereDistinct
|
||||||
|
on QueryBuilder<Account, Account, QDistinct> {
|
||||||
|
QueryBuilder<Account, Account, QDistinct> distinctByName({
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'name', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountQueryProperty
|
||||||
|
on QueryBuilder<Account, Account, QQueryProperty> {
|
||||||
|
QueryBuilder<Account, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Account, String?, QQueryOperations> nameProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
20
lib/database/collections/beneficiary.dart
Normal file
20
lib/database/collections/beneficiary.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
|
||||||
|
part 'beneficiary.g.dart';
|
||||||
|
|
||||||
|
enum BeneficiaryType { account, other }
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class Beneficiary {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
late String name;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.ordinal)
|
||||||
|
late BeneficiaryType type;
|
||||||
|
|
||||||
|
final account = IsarLink<Account>();
|
||||||
|
|
||||||
|
String? imagePath;
|
||||||
|
}
|
810
lib/database/collections/beneficiary.g.dart
Normal file
810
lib/database/collections/beneficiary.g.dart
Normal file
@ -0,0 +1,810 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'beneficiary.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetBeneficiaryCollection on Isar {
|
||||||
|
IsarCollection<Beneficiary> get beneficiarys => this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BeneficiarySchema = CollectionSchema(
|
||||||
|
name: r'Beneficiary',
|
||||||
|
id: -7106369371336791482,
|
||||||
|
properties: {
|
||||||
|
r'imagePath': PropertySchema(
|
||||||
|
id: 0,
|
||||||
|
name: r'imagePath',
|
||||||
|
type: IsarType.string,
|
||||||
|
),
|
||||||
|
r'name': PropertySchema(id: 1, name: r'name', type: IsarType.string),
|
||||||
|
r'type': PropertySchema(
|
||||||
|
id: 2,
|
||||||
|
name: r'type',
|
||||||
|
type: IsarType.byte,
|
||||||
|
enumMap: _BeneficiarytypeEnumValueMap,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
estimateSize: _beneficiaryEstimateSize,
|
||||||
|
serialize: _beneficiarySerialize,
|
||||||
|
deserialize: _beneficiaryDeserialize,
|
||||||
|
deserializeProp: _beneficiaryDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {
|
||||||
|
r'account': LinkSchema(
|
||||||
|
id: -725531860126526319,
|
||||||
|
name: r'account',
|
||||||
|
target: r'Account',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _beneficiaryGetId,
|
||||||
|
getLinks: _beneficiaryGetLinks,
|
||||||
|
attach: _beneficiaryAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _beneficiaryEstimateSize(
|
||||||
|
Beneficiary object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
{
|
||||||
|
final value = object.imagePath;
|
||||||
|
if (value != null) {
|
||||||
|
bytesCount += 3 + value.length * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytesCount += 3 + object.name.length * 3;
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _beneficiarySerialize(
|
||||||
|
Beneficiary object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeString(offsets[0], object.imagePath);
|
||||||
|
writer.writeString(offsets[1], object.name);
|
||||||
|
writer.writeByte(offsets[2], object.type.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Beneficiary _beneficiaryDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = Beneficiary();
|
||||||
|
object.id = id;
|
||||||
|
object.imagePath = reader.readStringOrNull(offsets[0]);
|
||||||
|
object.name = reader.readString(offsets[1]);
|
||||||
|
object.type =
|
||||||
|
_BeneficiarytypeValueEnumMap[reader.readByteOrNull(offsets[2])] ??
|
||||||
|
BeneficiaryType.account;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _beneficiaryDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readStringOrNull(offset)) as P;
|
||||||
|
case 1:
|
||||||
|
return (reader.readString(offset)) as P;
|
||||||
|
case 2:
|
||||||
|
return (_BeneficiarytypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||||
|
BeneficiaryType.account)
|
||||||
|
as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _BeneficiarytypeEnumValueMap = {'account': 0, 'other': 1};
|
||||||
|
const _BeneficiarytypeValueEnumMap = {
|
||||||
|
0: BeneficiaryType.account,
|
||||||
|
1: BeneficiaryType.other,
|
||||||
|
};
|
||||||
|
|
||||||
|
Id _beneficiaryGetId(Beneficiary object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _beneficiaryGetLinks(Beneficiary object) {
|
||||||
|
return [object.account];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _beneficiaryAttach(
|
||||||
|
IsarCollection<dynamic> col,
|
||||||
|
Id id,
|
||||||
|
Beneficiary object,
|
||||||
|
) {
|
||||||
|
object.id = id;
|
||||||
|
object.account.attach(col, col.isar.collection<Account>(), r'account', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryWhereSort
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QWhere> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryWhere
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QWhereClause> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhereClause> idEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhereClause> idNotEqualTo(
|
||||||
|
Id id,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhereClause> idGreaterThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhereClause> idLessThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterWhereClause> idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryFilter
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QFilterCondition> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> idEqualTo(
|
||||||
|
Id value,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> idGreaterThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> idLessThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNull(property: r'imagePath'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathIsNotNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNotNull(property: r'imagePath'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathEqualTo(String? value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathGreaterThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathLessThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathBetween(
|
||||||
|
String? lower,
|
||||||
|
String? upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'imagePath',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathStartsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathEndsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'imagePath',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'imagePath',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'imagePath', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
imagePathIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'imagePath', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameEqualTo(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameGreaterThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameLessThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameBetween(
|
||||||
|
String lower,
|
||||||
|
String upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'name',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameStartsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameEndsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameContains(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameMatches(
|
||||||
|
String pattern, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'name',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> nameIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
nameIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> typeEqualTo(
|
||||||
|
BeneficiaryType value,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'type', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> typeGreaterThan(
|
||||||
|
BeneficiaryType value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'type',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> typeLessThan(
|
||||||
|
BeneficiaryType value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'type',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> typeBetween(
|
||||||
|
BeneficiaryType lower,
|
||||||
|
BeneficiaryType upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'type',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryObject
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryLinks
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QFilterCondition> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition> account(
|
||||||
|
FilterQuery<Account> q,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'account');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterFilterCondition>
|
||||||
|
accountIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'account', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQuerySortBy
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QSortBy> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByImagePath() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'imagePath', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByImagePathDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'imagePath', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByType() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'type', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> sortByTypeDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'type', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQuerySortThenBy
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QSortThenBy> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByImagePath() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'imagePath', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByImagePathDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'imagePath', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByType() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'type', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QAfterSortBy> thenByTypeDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'type', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryWhereDistinct
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QDistinct> {
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QDistinct> distinctByImagePath({
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'imagePath', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QDistinct> distinctByName({
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'name', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, Beneficiary, QDistinct> distinctByType() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BeneficiaryQueryProperty
|
||||||
|
on QueryBuilder<Beneficiary, Beneficiary, QQueryProperty> {
|
||||||
|
QueryBuilder<Beneficiary, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, String?, QQueryOperations> imagePathProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'imagePath');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, String, QQueryOperations> nameProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Beneficiary, BeneficiaryType, QQueryOperations> typeProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
10
lib/database/collections/expense_category.dart
Normal file
10
lib/database/collections/expense_category.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
|
part 'expense_category.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class ExpenseCategory {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
late String name;
|
||||||
|
}
|
451
lib/database/collections/expense_category.g.dart
Normal file
451
lib/database/collections/expense_category.g.dart
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'expense_category.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetExpenseCategoryCollection on Isar {
|
||||||
|
IsarCollection<ExpenseCategory> get expenseCategorys => this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExpenseCategorySchema = CollectionSchema(
|
||||||
|
name: r'ExpenseCategory',
|
||||||
|
id: -6352499903118634,
|
||||||
|
properties: {
|
||||||
|
r'name': PropertySchema(id: 0, name: r'name', type: IsarType.string),
|
||||||
|
},
|
||||||
|
estimateSize: _expenseCategoryEstimateSize,
|
||||||
|
serialize: _expenseCategorySerialize,
|
||||||
|
deserialize: _expenseCategoryDeserialize,
|
||||||
|
deserializeProp: _expenseCategoryDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _expenseCategoryGetId,
|
||||||
|
getLinks: _expenseCategoryGetLinks,
|
||||||
|
attach: _expenseCategoryAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _expenseCategoryEstimateSize(
|
||||||
|
ExpenseCategory object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
bytesCount += 3 + object.name.length * 3;
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _expenseCategorySerialize(
|
||||||
|
ExpenseCategory object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeString(offsets[0], object.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpenseCategory _expenseCategoryDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = ExpenseCategory();
|
||||||
|
object.id = id;
|
||||||
|
object.name = reader.readString(offsets[0]);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _expenseCategoryDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readString(offset)) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _expenseCategoryGetId(ExpenseCategory object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _expenseCategoryGetLinks(ExpenseCategory object) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _expenseCategoryAttach(
|
||||||
|
IsarCollection<dynamic> col,
|
||||||
|
Id id,
|
||||||
|
ExpenseCategory object,
|
||||||
|
) {
|
||||||
|
object.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryWhereSort
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QWhere> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryWhere
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QWhereClause> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhereClause> idEqualTo(
|
||||||
|
Id id,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhereClause>
|
||||||
|
idNotEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhereClause>
|
||||||
|
idGreaterThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhereClause> idLessThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterWhereClause> idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryFilter
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QFilterCondition> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
idEqualTo(Id value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
idGreaterThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
idLessThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameEqualTo(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameGreaterThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameLessThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameBetween(
|
||||||
|
String lower,
|
||||||
|
String upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'name',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameStartsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameEndsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'name',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterFilterCondition>
|
||||||
|
nameIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryObject
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryLinks
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQuerySortBy
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QSortBy> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy> sortByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy>
|
||||||
|
sortByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQuerySortThenBy
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QSortThenBy> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy> thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy> thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy> thenByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QAfterSortBy>
|
||||||
|
thenByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryWhereDistinct
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QDistinct> {
|
||||||
|
QueryBuilder<ExpenseCategory, ExpenseCategory, QDistinct> distinctByName({
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'name', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExpenseCategoryQueryProperty
|
||||||
|
on QueryBuilder<ExpenseCategory, ExpenseCategory, QQueryProperty> {
|
||||||
|
QueryBuilder<ExpenseCategory, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<ExpenseCategory, String, QQueryOperations> nameProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
18
lib/database/collections/recurrent.dart
Normal file
18
lib/database/collections/recurrent.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/template.dart';
|
||||||
|
|
||||||
|
part 'recurrent.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class RecurringTransaction {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
late int days;
|
||||||
|
|
||||||
|
DateTime? lastExecution;
|
||||||
|
|
||||||
|
final template = IsarLink<TransactionTemplate>();
|
||||||
|
|
||||||
|
final account = IsarLink<Account>();
|
||||||
|
}
|
633
lib/database/collections/recurrent.g.dart
Normal file
633
lib/database/collections/recurrent.g.dart
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'recurrent.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetRecurringTransactionCollection on Isar {
|
||||||
|
IsarCollection<RecurringTransaction> get recurringTransactions =>
|
||||||
|
this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const RecurringTransactionSchema = CollectionSchema(
|
||||||
|
name: r'RecurringTransaction',
|
||||||
|
id: 969840479390105118,
|
||||||
|
properties: {
|
||||||
|
r'days': PropertySchema(id: 0, name: r'days', type: IsarType.long),
|
||||||
|
r'lastExecution': PropertySchema(
|
||||||
|
id: 1,
|
||||||
|
name: r'lastExecution',
|
||||||
|
type: IsarType.dateTime,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
estimateSize: _recurringTransactionEstimateSize,
|
||||||
|
serialize: _recurringTransactionSerialize,
|
||||||
|
deserialize: _recurringTransactionDeserialize,
|
||||||
|
deserializeProp: _recurringTransactionDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {
|
||||||
|
r'template': LinkSchema(
|
||||||
|
id: -8891369755965227865,
|
||||||
|
name: r'template',
|
||||||
|
target: r'TransactionTemplate',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
r'account': LinkSchema(
|
||||||
|
id: -6028551496614242115,
|
||||||
|
name: r'account',
|
||||||
|
target: r'Account',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _recurringTransactionGetId,
|
||||||
|
getLinks: _recurringTransactionGetLinks,
|
||||||
|
attach: _recurringTransactionAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _recurringTransactionEstimateSize(
|
||||||
|
RecurringTransaction object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _recurringTransactionSerialize(
|
||||||
|
RecurringTransaction object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeLong(offsets[0], object.days);
|
||||||
|
writer.writeDateTime(offsets[1], object.lastExecution);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecurringTransaction _recurringTransactionDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = RecurringTransaction();
|
||||||
|
object.days = reader.readLong(offsets[0]);
|
||||||
|
object.id = id;
|
||||||
|
object.lastExecution = reader.readDateTimeOrNull(offsets[1]);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _recurringTransactionDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readLong(offset)) as P;
|
||||||
|
case 1:
|
||||||
|
return (reader.readDateTimeOrNull(offset)) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _recurringTransactionGetId(RecurringTransaction object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _recurringTransactionGetLinks(
|
||||||
|
RecurringTransaction object,
|
||||||
|
) {
|
||||||
|
return [object.template, object.account];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _recurringTransactionAttach(
|
||||||
|
IsarCollection<dynamic> col,
|
||||||
|
Id id,
|
||||||
|
RecurringTransaction object,
|
||||||
|
) {
|
||||||
|
object.id = id;
|
||||||
|
object.template.attach(
|
||||||
|
col,
|
||||||
|
col.isar.collection<TransactionTemplate>(),
|
||||||
|
r'template',
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
object.account.attach(col, col.isar.collection<Account>(), r'account', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryWhereSort
|
||||||
|
on QueryBuilder<RecurringTransaction, RecurringTransaction, QWhere> {
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhere>
|
||||||
|
anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryWhere
|
||||||
|
on QueryBuilder<RecurringTransaction, RecurringTransaction, QWhereClause> {
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhereClause>
|
||||||
|
idEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhereClause>
|
||||||
|
idNotEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhereClause>
|
||||||
|
idGreaterThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhereClause>
|
||||||
|
idLessThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterWhereClause>
|
||||||
|
idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryFilter
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QFilterCondition
|
||||||
|
> {
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
daysEqualTo(int value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'days', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
daysGreaterThan(int value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'days',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
daysLessThan(int value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'days',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
daysBetween(
|
||||||
|
int lower,
|
||||||
|
int upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'days',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
idEqualTo(Id value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
idGreaterThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
idLessThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNull(property: r'lastExecution'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionIsNotNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
const FilterCondition.isNotNull(property: r'lastExecution'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionEqualTo(DateTime? value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'lastExecution', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionGreaterThan(DateTime? value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'lastExecution',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionLessThan(DateTime? value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'lastExecution',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
lastExecutionBetween(
|
||||||
|
DateTime? lower,
|
||||||
|
DateTime? upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'lastExecution',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryObject
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QFilterCondition
|
||||||
|
> {}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryLinks
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QFilterCondition
|
||||||
|
> {
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
template(FilterQuery<TransactionTemplate> q) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'template');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
templateIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'template', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
account(FilterQuery<Account> q) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'account');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QAfterFilterCondition
|
||||||
|
>
|
||||||
|
accountIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'account', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQuerySortBy
|
||||||
|
on QueryBuilder<RecurringTransaction, RecurringTransaction, QSortBy> {
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
sortByDays() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'days', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
sortByDaysDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'days', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
sortByLastExecution() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'lastExecution', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
sortByLastExecutionDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'lastExecution', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQuerySortThenBy
|
||||||
|
on QueryBuilder<RecurringTransaction, RecurringTransaction, QSortThenBy> {
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenByDays() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'days', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenByDaysDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'days', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenByLastExecution() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'lastExecution', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QAfterSortBy>
|
||||||
|
thenByLastExecutionDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'lastExecution', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryWhereDistinct
|
||||||
|
on QueryBuilder<RecurringTransaction, RecurringTransaction, QDistinct> {
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QDistinct>
|
||||||
|
distinctByDays() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'days');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, RecurringTransaction, QDistinct>
|
||||||
|
distinctByLastExecution() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'lastExecution');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RecurringTransactionQueryProperty
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
RecurringTransaction,
|
||||||
|
RecurringTransaction,
|
||||||
|
QQueryProperty
|
||||||
|
> {
|
||||||
|
QueryBuilder<RecurringTransaction, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, int, QQueryOperations> daysProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'days');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<RecurringTransaction, DateTime?, QQueryOperations>
|
||||||
|
lastExecutionProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'lastExecution');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
23
lib/database/collections/template.dart
Normal file
23
lib/database/collections/template.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
|
||||||
|
part 'template.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class TransactionTemplate {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
late String name;
|
||||||
|
|
||||||
|
late double amount;
|
||||||
|
|
||||||
|
late bool recurring;
|
||||||
|
|
||||||
|
final expenseCategory = IsarLink<ExpenseCategory>();
|
||||||
|
|
||||||
|
final beneficiary = IsarLink<Beneficiary>();
|
||||||
|
|
||||||
|
final account = IsarLink<Account>();
|
||||||
|
}
|
721
lib/database/collections/template.g.dart
Normal file
721
lib/database/collections/template.g.dart
Normal file
@ -0,0 +1,721 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'template.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetTransactionTemplateCollection on Isar {
|
||||||
|
IsarCollection<TransactionTemplate> get transactionTemplates =>
|
||||||
|
this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransactionTemplateSchema = CollectionSchema(
|
||||||
|
name: r'TransactionTemplate',
|
||||||
|
id: -2324989530163310644,
|
||||||
|
properties: {
|
||||||
|
r'amount': PropertySchema(id: 0, name: r'amount', type: IsarType.double),
|
||||||
|
r'name': PropertySchema(id: 1, name: r'name', type: IsarType.string),
|
||||||
|
r'recurring': PropertySchema(
|
||||||
|
id: 2,
|
||||||
|
name: r'recurring',
|
||||||
|
type: IsarType.bool,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
estimateSize: _transactionTemplateEstimateSize,
|
||||||
|
serialize: _transactionTemplateSerialize,
|
||||||
|
deserialize: _transactionTemplateDeserialize,
|
||||||
|
deserializeProp: _transactionTemplateDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {
|
||||||
|
r'expenseCategory': LinkSchema(
|
||||||
|
id: 3013186211408715712,
|
||||||
|
name: r'expenseCategory',
|
||||||
|
target: r'ExpenseCategory',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
r'beneficiary': LinkSchema(
|
||||||
|
id: -7565656011019083791,
|
||||||
|
name: r'beneficiary',
|
||||||
|
target: r'Beneficiary',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
r'account': LinkSchema(
|
||||||
|
id: 2465433941426054606,
|
||||||
|
name: r'account',
|
||||||
|
target: r'Account',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _transactionTemplateGetId,
|
||||||
|
getLinks: _transactionTemplateGetLinks,
|
||||||
|
attach: _transactionTemplateAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _transactionTemplateEstimateSize(
|
||||||
|
TransactionTemplate object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
bytesCount += 3 + object.name.length * 3;
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _transactionTemplateSerialize(
|
||||||
|
TransactionTemplate object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeDouble(offsets[0], object.amount);
|
||||||
|
writer.writeString(offsets[1], object.name);
|
||||||
|
writer.writeBool(offsets[2], object.recurring);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionTemplate _transactionTemplateDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = TransactionTemplate();
|
||||||
|
object.amount = reader.readDouble(offsets[0]);
|
||||||
|
object.id = id;
|
||||||
|
object.name = reader.readString(offsets[1]);
|
||||||
|
object.recurring = reader.readBool(offsets[2]);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _transactionTemplateDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readDouble(offset)) as P;
|
||||||
|
case 1:
|
||||||
|
return (reader.readString(offset)) as P;
|
||||||
|
case 2:
|
||||||
|
return (reader.readBool(offset)) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _transactionTemplateGetId(TransactionTemplate object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _transactionTemplateGetLinks(
|
||||||
|
TransactionTemplate object,
|
||||||
|
) {
|
||||||
|
return [object.expenseCategory, object.beneficiary, object.account];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _transactionTemplateAttach(
|
||||||
|
IsarCollection<dynamic> col,
|
||||||
|
Id id,
|
||||||
|
TransactionTemplate object,
|
||||||
|
) {
|
||||||
|
object.id = id;
|
||||||
|
object.expenseCategory.attach(
|
||||||
|
col,
|
||||||
|
col.isar.collection<ExpenseCategory>(),
|
||||||
|
r'expenseCategory',
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
object.beneficiary.attach(
|
||||||
|
col,
|
||||||
|
col.isar.collection<Beneficiary>(),
|
||||||
|
r'beneficiary',
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
object.account.attach(col, col.isar.collection<Account>(), r'account', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryWhereSort
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QWhere> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryWhere
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QWhereClause> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhereClause>
|
||||||
|
idEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhereClause>
|
||||||
|
idNotEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhereClause>
|
||||||
|
idGreaterThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhereClause>
|
||||||
|
idLessThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterWhereClause>
|
||||||
|
idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryFilter
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
TransactionTemplate,
|
||||||
|
TransactionTemplate,
|
||||||
|
QFilterCondition
|
||||||
|
> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
amountEqualTo(double value, {double epsilon = Query.epsilon}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
amountGreaterThan(
|
||||||
|
double value, {
|
||||||
|
bool include = false,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
amountLessThan(
|
||||||
|
double value, {
|
||||||
|
bool include = false,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
amountBetween(
|
||||||
|
double lower,
|
||||||
|
double upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'amount',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
idEqualTo(Id value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
idGreaterThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
idLessThan(Id value, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameEqualTo(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameGreaterThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameLessThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameBetween(
|
||||||
|
String lower,
|
||||||
|
String upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'name',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameStartsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameEndsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'name',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'name',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
nameIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'name', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
recurringEqualTo(bool value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'recurring', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryObject
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
TransactionTemplate,
|
||||||
|
TransactionTemplate,
|
||||||
|
QFilterCondition
|
||||||
|
> {}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryLinks
|
||||||
|
on
|
||||||
|
QueryBuilder<
|
||||||
|
TransactionTemplate,
|
||||||
|
TransactionTemplate,
|
||||||
|
QFilterCondition
|
||||||
|
> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
expenseCategory(FilterQuery<ExpenseCategory> q) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'expenseCategory');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
expenseCategoryIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'expenseCategory', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
beneficiary(FilterQuery<Beneficiary> q) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'beneficiary');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
beneficiaryIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'beneficiary', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
account(FilterQuery<Account> q) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'account');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterFilterCondition>
|
||||||
|
accountIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'account', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQuerySortBy
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QSortBy> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByAmountDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByRecurring() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'recurring', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
sortByRecurringDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'recurring', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQuerySortThenBy
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QSortThenBy> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByAmountDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByName() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByNameDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'name', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByRecurring() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'recurring', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QAfterSortBy>
|
||||||
|
thenByRecurringDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'recurring', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryWhereDistinct
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QDistinct> {
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QDistinct>
|
||||||
|
distinctByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'amount');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QDistinct>
|
||||||
|
distinctByName({bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'name', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, TransactionTemplate, QDistinct>
|
||||||
|
distinctByRecurring() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'recurring');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionTemplateQueryProperty
|
||||||
|
on QueryBuilder<TransactionTemplate, TransactionTemplate, QQueryProperty> {
|
||||||
|
QueryBuilder<TransactionTemplate, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, double, QQueryOperations> amountProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'amount');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, String, QQueryOperations> nameProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<TransactionTemplate, bool, QQueryOperations>
|
||||||
|
recurringProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'recurring');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
23
lib/database/collections/transaction.dart
Normal file
23
lib/database/collections/transaction.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
|
||||||
|
part 'transaction.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class Transaction {
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
late double amount;
|
||||||
|
|
||||||
|
late List<String> tags;
|
||||||
|
|
||||||
|
late DateTime date;
|
||||||
|
|
||||||
|
final expenseCategory = IsarLink<ExpenseCategory>();
|
||||||
|
|
||||||
|
final account = IsarLink<Account>();
|
||||||
|
|
||||||
|
final beneficiary = IsarLink<Beneficiary>();
|
||||||
|
}
|
775
lib/database/collections/transaction.g.dart
Normal file
775
lib/database/collections/transaction.g.dart
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'transaction.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// IsarCollectionGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||||
|
|
||||||
|
extension GetTransactionCollection on Isar {
|
||||||
|
IsarCollection<Transaction> get transactions => this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransactionSchema = CollectionSchema(
|
||||||
|
name: r'Transaction',
|
||||||
|
id: 5320225499417954855,
|
||||||
|
properties: {
|
||||||
|
r'amount': PropertySchema(id: 0, name: r'amount', type: IsarType.double),
|
||||||
|
r'date': PropertySchema(id: 1, name: r'date', type: IsarType.dateTime),
|
||||||
|
r'tags': PropertySchema(id: 2, name: r'tags', type: IsarType.stringList),
|
||||||
|
},
|
||||||
|
estimateSize: _transactionEstimateSize,
|
||||||
|
serialize: _transactionSerialize,
|
||||||
|
deserialize: _transactionDeserialize,
|
||||||
|
deserializeProp: _transactionDeserializeProp,
|
||||||
|
idName: r'id',
|
||||||
|
indexes: {},
|
||||||
|
links: {
|
||||||
|
r'expenseCategory': LinkSchema(
|
||||||
|
id: 490804775908778298,
|
||||||
|
name: r'expenseCategory',
|
||||||
|
target: r'ExpenseCategory',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
r'account': LinkSchema(
|
||||||
|
id: -8467990729867616553,
|
||||||
|
name: r'account',
|
||||||
|
target: r'Account',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
r'beneficiary': LinkSchema(
|
||||||
|
id: -1184196133247909686,
|
||||||
|
name: r'beneficiary',
|
||||||
|
target: r'Beneficiary',
|
||||||
|
single: true,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
embeddedSchemas: {},
|
||||||
|
getId: _transactionGetId,
|
||||||
|
getLinks: _transactionGetLinks,
|
||||||
|
attach: _transactionAttach,
|
||||||
|
version: '3.1.0+1',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _transactionEstimateSize(
|
||||||
|
Transaction object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
bytesCount += 3 + object.tags.length * 3;
|
||||||
|
{
|
||||||
|
for (var i = 0; i < object.tags.length; i++) {
|
||||||
|
final value = object.tags[i];
|
||||||
|
bytesCount += value.length * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _transactionSerialize(
|
||||||
|
Transaction object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeDouble(offsets[0], object.amount);
|
||||||
|
writer.writeDateTime(offsets[1], object.date);
|
||||||
|
writer.writeStringList(offsets[2], object.tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transaction _transactionDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = Transaction();
|
||||||
|
object.amount = reader.readDouble(offsets[0]);
|
||||||
|
object.date = reader.readDateTime(offsets[1]);
|
||||||
|
object.id = id;
|
||||||
|
object.tags = reader.readStringList(offsets[2]) ?? [];
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _transactionDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readDouble(offset)) as P;
|
||||||
|
case 1:
|
||||||
|
return (reader.readDateTime(offset)) as P;
|
||||||
|
case 2:
|
||||||
|
return (reader.readStringList(offset) ?? []) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _transactionGetId(Transaction object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _transactionGetLinks(Transaction object) {
|
||||||
|
return [object.expenseCategory, object.account, object.beneficiary];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _transactionAttach(
|
||||||
|
IsarCollection<dynamic> col,
|
||||||
|
Id id,
|
||||||
|
Transaction object,
|
||||||
|
) {
|
||||||
|
object.id = id;
|
||||||
|
object.expenseCategory.attach(
|
||||||
|
col,
|
||||||
|
col.isar.collection<ExpenseCategory>(),
|
||||||
|
r'expenseCategory',
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
object.account.attach(col, col.isar.collection<Account>(), r'account', id);
|
||||||
|
object.beneficiary.attach(
|
||||||
|
col,
|
||||||
|
col.isar.collection<Beneficiary>(),
|
||||||
|
r'beneficiary',
|
||||||
|
id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryWhereSort
|
||||||
|
on QueryBuilder<Transaction, Transaction, QWhere> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryWhere
|
||||||
|
on QueryBuilder<Transaction, Transaction, QWhereClause> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> idEqualTo(Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(lower: id, upper: id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> idNotEqualTo(
|
||||||
|
Id id,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
if (query.whereSort == Sort.asc) {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return query
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||||
|
)
|
||||||
|
.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> idGreaterThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> idLessThan(
|
||||||
|
Id id, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterWhereClause> idBetween(
|
||||||
|
Id lowerId,
|
||||||
|
Id upperId, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.between(
|
||||||
|
lower: lowerId,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upperId,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryFilter
|
||||||
|
on QueryBuilder<Transaction, Transaction, QFilterCondition> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> amountEqualTo(
|
||||||
|
double value, {
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
amountGreaterThan(
|
||||||
|
double value, {
|
||||||
|
bool include = false,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> amountLessThan(
|
||||||
|
double value, {
|
||||||
|
bool include = false,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'amount',
|
||||||
|
value: value,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> amountBetween(
|
||||||
|
double lower,
|
||||||
|
double upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
double epsilon = Query.epsilon,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'amount',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
epsilon: epsilon,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> dateEqualTo(
|
||||||
|
DateTime value,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'date', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> dateGreaterThan(
|
||||||
|
DateTime value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'date',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> dateLessThan(
|
||||||
|
DateTime value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'date',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> dateBetween(
|
||||||
|
DateTime lower,
|
||||||
|
DateTime upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'date',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> idEqualTo(
|
||||||
|
Id value,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'id', value: value),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> idGreaterThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> idLessThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> idBetween(
|
||||||
|
Id lower,
|
||||||
|
Id upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'id',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementEqualTo(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementGreaterThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementLessThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementBetween(
|
||||||
|
String lower,
|
||||||
|
String upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.between(
|
||||||
|
property: r'tags',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementStartsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.startsWith(
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementEndsWith(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.endsWith(
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.contains(
|
||||||
|
property: r'tags',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.matches(
|
||||||
|
property: r'tags',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.equalTo(property: r'tags', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsElementIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(
|
||||||
|
FilterCondition.greaterThan(property: r'tags', value: ''),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsLengthEqualTo(int length) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(r'tags', length, true, length, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> tagsIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(r'tags', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(r'tags', 0, false, 999999, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsLengthLessThan(int length, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(r'tags', 0, true, length, include);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsLengthGreaterThan(int length, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(r'tags', length, include, 999999, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
tagsLengthBetween(
|
||||||
|
int lower,
|
||||||
|
int upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'tags',
|
||||||
|
lower,
|
||||||
|
includeLower,
|
||||||
|
upper,
|
||||||
|
includeUpper,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryObject
|
||||||
|
on QueryBuilder<Transaction, Transaction, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension TransactionQueryLinks
|
||||||
|
on QueryBuilder<Transaction, Transaction, QFilterCondition> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> expenseCategory(
|
||||||
|
FilterQuery<ExpenseCategory> q,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'expenseCategory');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
expenseCategoryIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'expenseCategory', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> account(
|
||||||
|
FilterQuery<Account> q,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'account');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
accountIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'account', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition> beneficiary(
|
||||||
|
FilterQuery<Beneficiary> q,
|
||||||
|
) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.link(q, r'beneficiary');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterFilterCondition>
|
||||||
|
beneficiaryIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.linkLength(r'beneficiary', 0, true, 0, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQuerySortBy
|
||||||
|
on QueryBuilder<Transaction, Transaction, QSortBy> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> sortByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> sortByAmountDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> sortByDate() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'date', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> sortByDateDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'date', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQuerySortThenBy
|
||||||
|
on QueryBuilder<Transaction, Transaction, QSortThenBy> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenByAmountDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'amount', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenByDate() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'date', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenByDateDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'date', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QAfterSortBy> thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryWhereDistinct
|
||||||
|
on QueryBuilder<Transaction, Transaction, QDistinct> {
|
||||||
|
QueryBuilder<Transaction, Transaction, QDistinct> distinctByAmount() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'amount');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QDistinct> distinctByDate() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'date');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, Transaction, QDistinct> distinctByTags() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'tags');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransactionQueryProperty
|
||||||
|
on QueryBuilder<Transaction, Transaction, QQueryProperty> {
|
||||||
|
QueryBuilder<Transaction, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, double, QQueryOperations> amountProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'amount');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, DateTime, QQueryOperations> dateProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'date');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<Transaction, List<String>, QQueryOperations> tagsProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'tags');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
207
lib/database/database.dart
Normal file
207
lib/database/database.dart
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
import 'package:okane/database/collections/recurrent.dart';
|
||||||
|
import 'package:okane/database/collections/template.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
Future<Isar> openDatabase() async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
return Isar.open([
|
||||||
|
AccountSchema,
|
||||||
|
BeneficiarySchema,
|
||||||
|
TransactionSchema,
|
||||||
|
TransactionTemplateSchema,
|
||||||
|
RecurringTransactionSchema,
|
||||||
|
ExpenseCategorySchema,
|
||||||
|
], directory: dir.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Account>> getAccounts() {
|
||||||
|
return GetIt.I.get<Isar>().accounts.where().findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<double> getTotalBalance(Account account) async {
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.amountProperty()
|
||||||
|
.sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Transaction>> getLastTransactions(
|
||||||
|
Account account,
|
||||||
|
DateTime today,
|
||||||
|
int days,
|
||||||
|
) async {
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.dateGreaterThan(toMidnight(today.subtract(Duration(days: days))))
|
||||||
|
.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<RecurringTransaction>> getRecurringTransactions(Account? account) {
|
||||||
|
if (account == null) {
|
||||||
|
return Future.value([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.recurringTransactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchRecurringTransactions(Account account) {
|
||||||
|
final account = GetIt.I.get<CoreCubit>().activeAccount!;
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.recurringTransactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.build()
|
||||||
|
.watchLazy(fireImmediately: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertAccount(Account account) async {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() async {
|
||||||
|
print("Before account insert");
|
||||||
|
final id = await db.accounts.put(account);
|
||||||
|
print("After account insert: $id");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertBeneficiary(Beneficiary beneficiary) async {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() async {
|
||||||
|
await db.beneficiarys.put(beneficiary);
|
||||||
|
await beneficiary.account.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Beneficiary?> getAccountBeneficiary(Account account) {
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.beneficiarys
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertTransactionTemplate(TransactionTemplate template) async {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() async {
|
||||||
|
await db.transactionTemplates.put(template);
|
||||||
|
await template.beneficiary.save();
|
||||||
|
await template.account.save();
|
||||||
|
await template.expenseCategory.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertRecurringTransaction(RecurringTransaction template) async {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() async {
|
||||||
|
await db.recurringTransactions.put(template);
|
||||||
|
await template.template.save();
|
||||||
|
await template.account.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertTransaction(Transaction transaction) async {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() async {
|
||||||
|
await db.transactions.put(transaction);
|
||||||
|
await transaction.beneficiary.save();
|
||||||
|
await transaction.account.save();
|
||||||
|
await transaction.expenseCategory.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchAccounts() {
|
||||||
|
return GetIt.I.get<Isar>().accounts.watchLazy();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchTransactionTemplates(Account account) {
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactionTemplates
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.recurringEqualTo(false)
|
||||||
|
.watchLazy(fireImmediately: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<TransactionTemplate>> getTransactionTemplates(Account? account) {
|
||||||
|
if (account == null) {
|
||||||
|
return Future.value([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactionTemplates
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.recurringEqualTo(false)
|
||||||
|
.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchTransactions(Account account) {
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.watchLazy(fireImmediately: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Transaction>> getTransactions(Account? account) {
|
||||||
|
if (account == null) {
|
||||||
|
return Future.value([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetIt.I
|
||||||
|
.get<Isar>()
|
||||||
|
.transactions
|
||||||
|
.filter()
|
||||||
|
.account((q) => q.idEqualTo(account.id))
|
||||||
|
.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchBeneficiaries() {
|
||||||
|
return GetIt.I.get<Isar>().beneficiarys.watchLazy(fireImmediately: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Beneficiary>> getBeneficiaries() {
|
||||||
|
return GetIt.I.get<Isar>().beneficiarys.where().findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<Beneficiary?> watchBeneficiaryObject(Id id) {
|
||||||
|
return GetIt.I.get<Isar>().beneficiarys.watchObject(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> upsertExpenseCategory(ExpenseCategory category) {
|
||||||
|
final db = GetIt.I.get<Isar>();
|
||||||
|
return db.writeTxn(() => db.expenseCategorys.put(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ExpenseCategory>> getExpenseCategories() {
|
||||||
|
return GetIt.I.get<Isar>().expenseCategorys.where().findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<void> watchExpenseCategory() {
|
||||||
|
return GetIt.I.get<Isar>().expenseCategorys.watchLazy(fireImmediately: true);
|
||||||
|
}
|
107
lib/main.dart
Normal file
107
lib/main.dart
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/screen.dart';
|
||||||
|
import 'package:okane/ui/navigation.dart';
|
||||||
|
import 'package:okane/ui/pages/transaction_details.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
GetIt.I.registerSingleton<CoreCubit>(CoreCubit());
|
||||||
|
GetIt.I.registerSingleton<Isar>(await openDatabase());
|
||||||
|
|
||||||
|
runApp(const MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
// This widget is the root of your application.
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MultiBlocProvider(
|
||||||
|
providers: [
|
||||||
|
BlocProvider<CoreCubit>(create: (_) => GetIt.I.get<CoreCubit>()),
|
||||||
|
],
|
||||||
|
child: MaterialApp(
|
||||||
|
title: 'Flutter Demo',
|
||||||
|
theme: ThemeData(
|
||||||
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
|
),
|
||||||
|
home: const MyHomePage(),
|
||||||
|
onGenerateRoute:
|
||||||
|
(settings) => switch (settings.name) {
|
||||||
|
"/transactions/details" => TransactionDetailsPage.mobileRoute,
|
||||||
|
_ => MaterialPageRoute<void>(builder: (_) => Text("Unknown!!")),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHomePage extends StatefulWidget {
|
||||||
|
const MyHomePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
final Completer<int> _initCompleter = Completer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
asyncInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> asyncInit() async {
|
||||||
|
print("Starting async init");
|
||||||
|
await GetIt.I.get<CoreCubit>().init();
|
||||||
|
_initCompleter.complete(1);
|
||||||
|
print("Async init done");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final screenSize = getScreenSize(context);
|
||||||
|
if (screenSize == ScreenSize.normal) {
|
||||||
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return FutureBuilder(
|
||||||
|
future: _initCompleter.future,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
print("${snapshot.hasData}");
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
bottomNavigationBar: switch (screenSize) {
|
||||||
|
ScreenSize.normal => null,
|
||||||
|
ScreenSize.small => OkaneNavigationBar(),
|
||||||
|
},
|
||||||
|
body: switch (screenSize) {
|
||||||
|
ScreenSize.normal => const Row(
|
||||||
|
children: [
|
||||||
|
OkaneNavigationRail(),
|
||||||
|
VerticalDivider(thickness: 1, width: 1),
|
||||||
|
Expanded(child: OkaneNavigationLayout()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ScreenSize.small => const OkaneNavigationLayout(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
lib/screen.dart
Normal file
17
lib/screen.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
enum ScreenSize {
|
||||||
|
small(300),
|
||||||
|
normal(400);
|
||||||
|
|
||||||
|
final double size;
|
||||||
|
|
||||||
|
const ScreenSize(this.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenSize getScreenSize(BuildContext context) {
|
||||||
|
final width = MediaQuery.sizeOf(context).shortestSide;
|
||||||
|
if (width > ScreenSize.normal.size) return ScreenSize.normal;
|
||||||
|
|
||||||
|
return ScreenSize.small;
|
||||||
|
}
|
138
lib/ui/navigation.dart
Normal file
138
lib/ui/navigation.dart
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:okane/screen.dart';
|
||||||
|
import 'package:okane/ui/pages/account/account.dart';
|
||||||
|
import 'package:okane/ui/pages/template_list.dart';
|
||||||
|
import 'package:okane/ui/pages/transaction_details.dart';
|
||||||
|
import 'package:okane/ui/pages/transaction_list.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
|
||||||
|
enum OkanePage { accounts, transactions, beneficiaries, templates, budgets }
|
||||||
|
|
||||||
|
typedef OkanePageBuilder = Widget Function(bool);
|
||||||
|
|
||||||
|
class OkanePageItem {
|
||||||
|
final OkanePage page;
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final Widget child;
|
||||||
|
final OkanePageBuilder? details;
|
||||||
|
|
||||||
|
const OkanePageItem(
|
||||||
|
this.page,
|
||||||
|
this.icon,
|
||||||
|
this.label,
|
||||||
|
this.child,
|
||||||
|
this.details,
|
||||||
|
);
|
||||||
|
|
||||||
|
NavigationDestination toDestination() =>
|
||||||
|
NavigationDestination(icon: Icon(icon), label: label);
|
||||||
|
|
||||||
|
NavigationRailDestination toRailDestination() =>
|
||||||
|
NavigationRailDestination(icon: Icon(icon), label: Text(label));
|
||||||
|
}
|
||||||
|
|
||||||
|
final _pages = <OkanePageItem>[
|
||||||
|
OkanePageItem(
|
||||||
|
OkanePage.accounts,
|
||||||
|
Icons.account_box,
|
||||||
|
"Accounts",
|
||||||
|
AccountListPage(isPage: false),
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
OkanePageItem(
|
||||||
|
OkanePage.transactions,
|
||||||
|
Icons.monetization_on_rounded,
|
||||||
|
"Transactions",
|
||||||
|
TransactionListPage(),
|
||||||
|
(_) => TransactionDetailsPage(),
|
||||||
|
),
|
||||||
|
OkanePageItem(
|
||||||
|
OkanePage.beneficiaries,
|
||||||
|
Icons.person,
|
||||||
|
"Beneficiaries",
|
||||||
|
Container(),
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
OkanePageItem(
|
||||||
|
OkanePage.templates,
|
||||||
|
Icons.list,
|
||||||
|
"Templates",
|
||||||
|
TemplateListPage(),
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
OkanePageItem(
|
||||||
|
OkanePage.budgets,
|
||||||
|
Icons.pie_chart,
|
||||||
|
"Budgets",
|
||||||
|
Placeholder(),
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
class OkaneNavigationRail extends StatelessWidget {
|
||||||
|
const OkaneNavigationRail({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => NavigationRail(
|
||||||
|
onDestinationSelected:
|
||||||
|
(i) => context.read<CoreCubit>().setPage(_pages[i].page),
|
||||||
|
destinations: _pages.map((p) => p.toRailDestination()).toList(),
|
||||||
|
selectedIndex: _pages.indexWhere((p) => p.page == state.activePage),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OkaneNavigationBar extends StatelessWidget {
|
||||||
|
const OkaneNavigationBar({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => NavigationBar(
|
||||||
|
onDestinationSelected:
|
||||||
|
(i) => context.read<CoreCubit>().setPage(_pages[i].page),
|
||||||
|
destinations: _pages.map((p) => p.toDestination()).toList(),
|
||||||
|
selectedIndex: _pages.indexWhere((p) => p.page == state.activePage),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OkaneNavigationLayout extends StatelessWidget {
|
||||||
|
const OkaneNavigationLayout({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final screenSize = getScreenSize(context);
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(_, state) => IndexedStack(
|
||||||
|
index: _pages.indexWhere((p) => p.page == state.activePage),
|
||||||
|
children:
|
||||||
|
_pages
|
||||||
|
.map(
|
||||||
|
(p) => switch (screenSize) {
|
||||||
|
ScreenSize.small => p.child,
|
||||||
|
ScreenSize.normal =>
|
||||||
|
p.details != null
|
||||||
|
? Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: p.child),
|
||||||
|
Expanded(child: p.details!(false)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: p.child,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
191
lib/ui/pages/account/account.dart
Normal file
191
lib/ui/pages/account/account.dart
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/pages/account/breakdown_card.dart';
|
||||||
|
import 'package:okane/ui/pages/account/total_balance_card.dart';
|
||||||
|
import 'package:okane/ui/pages/account/upcoming_transactions_card.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
|
||||||
|
class AccountListPage extends StatefulWidget {
|
||||||
|
final bool isPage;
|
||||||
|
|
||||||
|
const AccountListPage({required this.isPage, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
AccountListPageState createState() => AccountListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountListPageState extends State<AccountListPage> {
|
||||||
|
final TextEditingController _accountNameController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: Text(
|
||||||
|
"Accounts",
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => SizedBox(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 100,
|
||||||
|
child: ListView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: state.accounts.length,
|
||||||
|
itemBuilder:
|
||||||
|
(context, index) => SizedBox(
|
||||||
|
width: 150,
|
||||||
|
height: 100,
|
||||||
|
child: Card(
|
||||||
|
color: colorHash(state.accounts[index].name!),
|
||||||
|
shape:
|
||||||
|
index == state.activeAccountIndex
|
||||||
|
? RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: Colors.black,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
12,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
GetIt.I
|
||||||
|
.get<CoreCubit>()
|
||||||
|
.setActiveAccountIndex(index);
|
||||||
|
},
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(state.accounts[index].name!),
|
||||||
|
FutureBuilder(
|
||||||
|
future: getTotalBalance(
|
||||||
|
state.accounts[index],
|
||||||
|
),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
formatCurrency(snapshot.data!),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: TotalBalanceCard(),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: UpcomingTransactionsCard(),
|
||||||
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: AccountBalanceGraphCard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),*/
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Padding(padding: EdgeInsets.all(16), child: BreakdownCard()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 16,
|
||||||
|
bottom: 16,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
child: Icon(Icons.add),
|
||||||
|
onPressed: () {
|
||||||
|
showDialogOrModal(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(ctx) => Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 8,
|
||||||
|
horizontal: 16,
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
controller: _accountNameController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Account name",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (_accountNameController.text.isEmpty) return;
|
||||||
|
|
||||||
|
final a =
|
||||||
|
Account()..name = _accountNameController.text;
|
||||||
|
final b =
|
||||||
|
Beneficiary()
|
||||||
|
..name = _accountNameController.text
|
||||||
|
..account.value =
|
||||||
|
GetIt.I.get<CoreCubit>().activeAccount
|
||||||
|
..type = BeneficiaryType.account;
|
||||||
|
await upsertAccount(a);
|
||||||
|
await upsertBeneficiary(b);
|
||||||
|
_accountNameController.text = "";
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text("Add"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
150
lib/ui/pages/account/balance_graph_card.dart
Normal file
150
lib/ui/pages/account/balance_graph_card.dart
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
|
||||||
|
double getBalanceGraphScaling(double maxBalance) {
|
||||||
|
if (maxBalance < 100) {
|
||||||
|
return 10;
|
||||||
|
} else if (maxBalance < 1000) {
|
||||||
|
return 200;
|
||||||
|
} else if (maxBalance < 10000) {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountBalanceGraphCard extends StatelessWidget {
|
||||||
|
const AccountBalanceGraphCard({super.key});
|
||||||
|
|
||||||
|
Future<List<FlSpot>> getAccountBalance() async {
|
||||||
|
final coreCubit = GetIt.I.get<CoreCubit>();
|
||||||
|
final today = toMidnight(DateTime.now());
|
||||||
|
final transactions = await getLastTransactions(
|
||||||
|
coreCubit.activeAccount!,
|
||||||
|
today,
|
||||||
|
30,
|
||||||
|
);
|
||||||
|
final totalBalance = await getTotalBalance(coreCubit.activeAccount!);
|
||||||
|
|
||||||
|
// Compute the differences per day
|
||||||
|
Map<int, double> differences = Map.fromEntries(
|
||||||
|
List.generate(30, (i) => i).map((i) => MapEntry(i, 0)),
|
||||||
|
);
|
||||||
|
for (final item in transactions) {
|
||||||
|
final diff = today.difference(toMidnight(item.date)).inDays;
|
||||||
|
final balance = differences[diff]!;
|
||||||
|
differences[diff] = balance + item.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the balance
|
||||||
|
final balances = HashMap<int, double>();
|
||||||
|
balances[0] = totalBalance;
|
||||||
|
for (final idx in List.generate(29, (i) => i + 1)) {
|
||||||
|
balances[idx] = balances[idx - 1]! + differences[idx]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FlSpot> result = List.empty(growable: true);
|
||||||
|
result.add(FlSpot(0, totalBalance));
|
||||||
|
result.addAll(
|
||||||
|
List.generate(
|
||||||
|
28,
|
||||||
|
(i) => i + 1,
|
||||||
|
).map((i) => FlSpot(i.toDouble(), balances[i]!)),
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text("Account balance"),
|
||||||
|
SizedBox(
|
||||||
|
height: 150,
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: getAccountBalance(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
final today = DateTime.now();
|
||||||
|
final maxBalance = snapshot.data!
|
||||||
|
.map((spot) => spot.y)
|
||||||
|
.reduce((acc, y) => y > acc ? y : acc);
|
||||||
|
return LineChart(
|
||||||
|
LineChartData(
|
||||||
|
minY:
|
||||||
|
snapshot.data!
|
||||||
|
.map((spot) => spot.y)
|
||||||
|
.reduce((acc, y) => y < acc ? y : acc) -
|
||||||
|
20,
|
||||||
|
maxY: maxBalance + 20,
|
||||||
|
titlesData: FlTitlesData(
|
||||||
|
bottomTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
interval: 4,
|
||||||
|
showTitles: true,
|
||||||
|
reservedSize: 40,
|
||||||
|
getTitlesWidget: (val, meta) {
|
||||||
|
final day = today.subtract(
|
||||||
|
Duration(days: val.toInt()),
|
||||||
|
);
|
||||||
|
return SideTitleWidget(
|
||||||
|
meta: meta,
|
||||||
|
child: Text(
|
||||||
|
formatDateTime(day, formatYear: false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leftTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: true,
|
||||||
|
reservedSize: 50,
|
||||||
|
interval: getBalanceGraphScaling(maxBalance),
|
||||||
|
getTitlesWidget:
|
||||||
|
(value, meta) => SideTitleWidget(
|
||||||
|
meta: meta,
|
||||||
|
child: Text(
|
||||||
|
formatCurrency(value, precise: false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
rightTitles: const AxisTitles(
|
||||||
|
sideTitles: SideTitles(showTitles: false),
|
||||||
|
),
|
||||||
|
topTitles: const AxisTitles(
|
||||||
|
sideTitles: SideTitles(showTitles: false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
gridData: const FlGridData(show: false),
|
||||||
|
lineBarsData: [
|
||||||
|
LineChartBarData(
|
||||||
|
isCurved: false,
|
||||||
|
barWidth: 3,
|
||||||
|
dotData: const FlDotData(show: false),
|
||||||
|
spots: snapshot.data!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
172
lib/ui/pages/account/breakdown_card.dart
Normal file
172
lib/ui/pages/account/breakdown_card.dart
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
|
||||||
|
const CATEGORY_INCOME = "Income";
|
||||||
|
const CATEGORY_OTHER = "Other";
|
||||||
|
|
||||||
|
typedef LegendData =
|
||||||
|
({Map<String, double> expenses, Map<String, Color> colors, double usable});
|
||||||
|
|
||||||
|
class LegendItem extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const LegendItem({required this.text, required this.color, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
child: SizedBox(width: 10, height: 10),
|
||||||
|
),
|
||||||
|
Padding(padding: EdgeInsets.only(left: 8), child: Text(text)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BreakdownCard extends StatelessWidget {
|
||||||
|
const BreakdownCard({super.key});
|
||||||
|
|
||||||
|
LegendData _computeSections(List<Transaction> transactions) {
|
||||||
|
Map<String, double> expenses = {};
|
||||||
|
Map<String, Color> colors = {};
|
||||||
|
double usableMoney = 0;
|
||||||
|
transactions.forEach((t) {
|
||||||
|
String category;
|
||||||
|
if (t.amount > 0) {
|
||||||
|
category = CATEGORY_INCOME;
|
||||||
|
colors[CATEGORY_INCOME] = Colors.green;
|
||||||
|
} else {
|
||||||
|
if (t.expenseCategory.value?.name == null) {
|
||||||
|
category = CATEGORY_OTHER;
|
||||||
|
colors[category] = Colors.red;
|
||||||
|
} else {
|
||||||
|
category = t.expenseCategory.value!.name;
|
||||||
|
colors[category] = colorHash(t.expenseCategory.value!.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expenses.update(
|
||||||
|
category,
|
||||||
|
(value) => value + t.amount.abs(),
|
||||||
|
ifAbsent: () => t.amount.abs(),
|
||||||
|
);
|
||||||
|
usableMoney += t.amount;
|
||||||
|
});
|
||||||
|
return (expenses: expenses, colors: colors, usable: usableMoney);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final bloc = GetIt.I.get<CoreCubit>();
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (bloc.activeAccount == null) {
|
||||||
|
return Text("No active account");
|
||||||
|
}
|
||||||
|
|
||||||
|
return FutureBuilder(
|
||||||
|
future: getLastTransactions(
|
||||||
|
bloc.activeAccount!,
|
||||||
|
DateTime.now(),
|
||||||
|
30,
|
||||||
|
),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final title = Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 16),
|
||||||
|
child: Text("Expense Breakdown"),
|
||||||
|
);
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return Column(children: [title, CircularProgressIndicator()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.data!.isEmpty) {
|
||||||
|
return Column(children: [title, Text("No transactions")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
final data = _computeSections(snapshot.data!);
|
||||||
|
final sectionData =
|
||||||
|
data.expenses.entries
|
||||||
|
.map(
|
||||||
|
(entry) => PieChartSectionData(
|
||||||
|
value: entry.value,
|
||||||
|
title: formatCurrency(entry.value, precise: false),
|
||||||
|
titleStyle: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
radius: 40,
|
||||||
|
color: data.colors[entry.key]!,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
title,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 150,
|
||||||
|
height: 150,
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: PieChart(
|
||||||
|
PieChartData(
|
||||||
|
borderData: FlBorderData(show: false),
|
||||||
|
sectionsSpace: 0,
|
||||||
|
centerSpaceRadius: 35,
|
||||||
|
sections: sectionData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children:
|
||||||
|
data.expenses.keys
|
||||||
|
.map(
|
||||||
|
(key) => LegendItem(
|
||||||
|
text: key,
|
||||||
|
color: data.colors[key]!,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 16),
|
||||||
|
child: Text(
|
||||||
|
"Available money: ${formatCurrency(data.usable)}",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
49
lib/ui/pages/account/total_balance_card.dart
Normal file
49
lib/ui/pages/account/total_balance_card.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
|
||||||
|
class TotalBalanceCard extends StatelessWidget {
|
||||||
|
const TotalBalanceCard({super.key});
|
||||||
|
|
||||||
|
Future<double> _getTotalBalance(List<Account> accounts) async {
|
||||||
|
if (accounts.isEmpty) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final results = await Future.wait(accounts.map(getTotalBalance).toList());
|
||||||
|
|
||||||
|
return results.reduce((acc, val) => acc + val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text("Total balance"),
|
||||||
|
FutureBuilder(
|
||||||
|
future: _getTotalBalance(state.accounts),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return Text("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(formatCurrency(snapshot.data!));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
69
lib/ui/pages/account/upcoming_transactions_card.dart
Normal file
69
lib/ui/pages/account/upcoming_transactions_card.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:okane/database/collections/recurrent.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
|
||||||
|
class UpcomingTransactionsCard extends StatelessWidget {
|
||||||
|
const UpcomingTransactionsCard({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final today = DateTime.now();
|
||||||
|
final upcomingRaw =
|
||||||
|
state.recurringTransactions.where((t) {
|
||||||
|
if (t.lastExecution == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return today.difference(t.lastExecution!).inDays <=
|
||||||
|
(t.days * 1.5).toInt();
|
||||||
|
}).toList();
|
||||||
|
final List<RecurringTransaction> upcoming =
|
||||||
|
upcomingRaw.isEmpty
|
||||||
|
? List.empty()
|
||||||
|
: upcomingRaw.sublist(0, min(upcomingRaw.length, 3));
|
||||||
|
final transactions =
|
||||||
|
upcoming.isEmpty
|
||||||
|
? [Text("No upcoming transactions")]
|
||||||
|
: upcoming
|
||||||
|
.map(
|
||||||
|
(t) => ListTile(
|
||||||
|
title: Text(
|
||||||
|
"${t.template.value!.name} (${t.template.value!.amount}€)",
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
"Due in ${today.difference(t.lastExecution ?? today).inDays} days",
|
||||||
|
),
|
||||||
|
leading: Icon(
|
||||||
|
t.template.value!.amount < 0
|
||||||
|
? Icons.remove
|
||||||
|
: Icons.add,
|
||||||
|
color:
|
||||||
|
t.template.value!.amount < 0
|
||||||
|
? Colors.red
|
||||||
|
: Colors.green,
|
||||||
|
),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: Icon(Icons.play_arrow),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[Text("Upcoming Transactions")] + transactions,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
75
lib/ui/pages/template_list.dart
Normal file
75
lib/ui/pages/template_list.dart
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/add_template.dart';
|
||||||
|
|
||||||
|
class TemplateListPage extends StatefulWidget {
|
||||||
|
const TemplateListPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TemplateListPage> createState() => TemplateListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TemplateListState extends State<TemplateListPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final account = GetIt.I.get<CoreCubit>().activeAccount;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 16),
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: state.recurringTransactions.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder:
|
||||||
|
(ctx, idx) => Card(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
state
|
||||||
|
.recurringTransactions[idx]
|
||||||
|
.template
|
||||||
|
.value!
|
||||||
|
.name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 16,
|
||||||
|
bottom: 16,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
child: Icon(Icons.add),
|
||||||
|
onPressed:
|
||||||
|
account == null
|
||||||
|
? () {}
|
||||||
|
: () {
|
||||||
|
showDialogOrModal(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(ctx) => AddTransactionTemplateWidget(
|
||||||
|
activeAccountItem: account,
|
||||||
|
onAdd: () {
|
||||||
|
setState(() {});
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
showDragHandle: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
118
lib/ui/pages/transaction_details.dart
Normal file
118
lib/ui/pages/transaction_details.dart
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/image_wrapper.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
|
class TransactionDetailsPage extends StatelessWidget {
|
||||||
|
final bool isPage;
|
||||||
|
|
||||||
|
const TransactionDetailsPage({this.isPage = false, super.key});
|
||||||
|
|
||||||
|
static MaterialPageRoute<void> get mobileRoute =>
|
||||||
|
MaterialPageRoute(builder: (_) => TransactionDetailsPage(isPage: true));
|
||||||
|
|
||||||
|
Future<void> _updateBeneficiaryIcon(Beneficiary beneficiary) async {
|
||||||
|
final pickedFile = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.image,
|
||||||
|
);
|
||||||
|
if (pickedFile == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final file = pickedFile.files.first;
|
||||||
|
final suppPath = await getApplicationSupportDirectory();
|
||||||
|
final imageDir = p.join(suppPath.path, "beneficiaries");
|
||||||
|
final imagePath = p.join(imageDir, file.name);
|
||||||
|
print("Copying ${file.path!} to $imagePath");
|
||||||
|
|
||||||
|
await Directory(imageDir).create(recursive: true);
|
||||||
|
if (beneficiary.imagePath != null) {
|
||||||
|
await File(beneficiary.imagePath!).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
await File(file.path!).copy(imagePath);
|
||||||
|
|
||||||
|
print("Updating DB");
|
||||||
|
beneficiary.imagePath = imagePath;
|
||||||
|
await upsertBeneficiary(beneficiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final widget = BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state.activeTransaction == null) {
|
||||||
|
return Text("No transaction selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
StreamBuilder(
|
||||||
|
stream: watchBeneficiaryObject(
|
||||||
|
state.activeTransaction!.beneficiary.value!.id,
|
||||||
|
),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final obj =
|
||||||
|
snapshot.data ??
|
||||||
|
state.activeTransaction!.beneficiary.value!;
|
||||||
|
return ImageWrapper(
|
||||||
|
title: obj.name,
|
||||||
|
path: obj.imagePath,
|
||||||
|
onTap: () => _updateBeneficiaryIcon(obj),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8),
|
||||||
|
child: Text(
|
||||||
|
state.activeTransaction!.beneficiary.value!.name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
children:
|
||||||
|
state.activeTransaction!.tags
|
||||||
|
.map((tag) => Chip(label: Text(tag)))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
state.activeTransaction!.amount > 0
|
||||||
|
? Icon(Icons.add)
|
||||||
|
: Icon(Icons.remove),
|
||||||
|
Text(formatCurrency(state.activeTransaction!.amount)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isPage) {
|
||||||
|
return Scaffold(body: widget);
|
||||||
|
}
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
}
|
163
lib/ui/pages/transaction_list.dart
Normal file
163
lib/ui/pages/transaction_list.dart
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:grouped_list/grouped_list.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/screen.dart';
|
||||||
|
import 'package:okane/ui/pages/account/balance_graph_card.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/add_transaction.dart';
|
||||||
|
import 'package:okane/ui/widgets/transaction_card.dart';
|
||||||
|
|
||||||
|
class TransactionListPage extends StatefulWidget {
|
||||||
|
const TransactionListPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TransactionListPage> createState() => TransactionListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransactionListState extends State<TransactionListPage> {
|
||||||
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final account = GetIt.I.get<CoreCubit>().activeAccount;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
CustomScrollView(
|
||||||
|
controller: _scrollController,
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: AccountBalanceGraphCard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: GroupedListView(
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
elements: state.transactions,
|
||||||
|
reverse: true,
|
||||||
|
groupBy: (Transaction item) => formatDateTime(item.date),
|
||||||
|
groupHeaderBuilder:
|
||||||
|
(item) => Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black.withAlpha(170),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
formatDateTime(item.date),
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
shrinkWrap: true,
|
||||||
|
indexedItemBuilder:
|
||||||
|
(ctx, item, idx) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: TransactionCard(
|
||||||
|
transaction: item,
|
||||||
|
onTap: () {
|
||||||
|
GetIt.I.get<CoreCubit>().setActiveTransaction(
|
||||||
|
item,
|
||||||
|
);
|
||||||
|
if (getScreenSize(ctx) == ScreenSize.small) {
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pushNamed("/transactions/details");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
/*Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 16),
|
||||||
|
child: GroupedListView(
|
||||||
|
elements: state.transactions,
|
||||||
|
reverse: true,
|
||||||
|
groupBy:
|
||||||
|
(Transaction item) => formatDateTime(item.date),
|
||||||
|
groupHeaderBuilder:
|
||||||
|
(item) => Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black.withAlpha(170),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
formatDateTime(item.date),
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
shrinkWrap: true,
|
||||||
|
indexedItemBuilder:
|
||||||
|
(ctx, item, idx) => TransactionCard(
|
||||||
|
transaction: item,
|
||||||
|
onTap: () {
|
||||||
|
GetIt.I.get<CoreCubit>().setActiveTransaction(
|
||||||
|
item,
|
||||||
|
);
|
||||||
|
if (getScreenSize(ctx) == ScreenSize.small) {
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pushNamed("/transactions/details");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),*/
|
||||||
|
Positioned(
|
||||||
|
right: 16,
|
||||||
|
bottom: 16,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
child: Icon(Icons.add),
|
||||||
|
onPressed:
|
||||||
|
account == null
|
||||||
|
? () {}
|
||||||
|
: () {
|
||||||
|
showDialogOrModal(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(ctx) => AddTransactionWidget(
|
||||||
|
activeAccountItem: account,
|
||||||
|
onAdd: () {
|
||||||
|
setState(() {});
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
showDragHandle: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
152
lib/ui/state/core.dart
Normal file
152
lib/ui/state/core.dart
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
import 'package:okane/database/collections/recurrent.dart';
|
||||||
|
import 'package:okane/database/collections/template.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/navigation.dart';
|
||||||
|
|
||||||
|
part 'core.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class CoreState with _$CoreState {
|
||||||
|
const factory CoreState({
|
||||||
|
@Default(OkanePage.accounts) OkanePage activePage,
|
||||||
|
int? activeAccountIndex,
|
||||||
|
@Default(null) Transaction? activeTransaction,
|
||||||
|
@Default([]) List<Account> accounts,
|
||||||
|
@Default([]) List<RecurringTransaction> recurringTransactions,
|
||||||
|
@Default([]) List<Transaction> transactions,
|
||||||
|
@Default([]) List<TransactionTemplate> transactionTemplates,
|
||||||
|
@Default([]) List<Beneficiary> beneficiaries,
|
||||||
|
@Default([]) List<ExpenseCategory> expenseCategories,
|
||||||
|
}) = _CoreState;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoreCubit extends Cubit<CoreState> {
|
||||||
|
CoreCubit() : super(CoreState());
|
||||||
|
|
||||||
|
StreamSubscription<void>? _recurringTransactionStreamSubscription;
|
||||||
|
StreamSubscription<void>? _transactionTemplatesStreamSubcription;
|
||||||
|
StreamSubscription<void>? _accountsStreamSubscription;
|
||||||
|
StreamSubscription<void>? _transactionsStreamSubscription;
|
||||||
|
StreamSubscription<void>? _beneficiariesStreamSubscription;
|
||||||
|
StreamSubscription<void>? _expenseCategoryStreamSubscription;
|
||||||
|
|
||||||
|
void setupAccountStream() {
|
||||||
|
_accountsStreamSubscription?.cancel();
|
||||||
|
_accountsStreamSubscription = watchAccounts().listen((_) async {
|
||||||
|
final resetStreams = state.activeAccountIndex == null;
|
||||||
|
final accounts = await getAccounts();
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
accounts: accounts,
|
||||||
|
activeAccountIndex: state.activeAccountIndex ?? 0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resetStreams) {
|
||||||
|
setupStreams(accounts[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupStreams(Account account) {
|
||||||
|
setupAccountStream();
|
||||||
|
_recurringTransactionStreamSubscription?.cancel();
|
||||||
|
_recurringTransactionStreamSubscription = watchRecurringTransactions(
|
||||||
|
activeAccount!,
|
||||||
|
).listen((_) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
recurringTransactions: await getRecurringTransactions(activeAccount!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_transactionTemplatesStreamSubcription?.cancel();
|
||||||
|
_transactionTemplatesStreamSubcription = watchTransactionTemplates(
|
||||||
|
activeAccount!,
|
||||||
|
).listen((_) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
transactionTemplates: await getTransactionTemplates(activeAccount!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_transactionsStreamSubscription?.cancel();
|
||||||
|
_transactionsStreamSubscription = watchTransactions(activeAccount!).listen((
|
||||||
|
_,
|
||||||
|
) async {
|
||||||
|
emit(state.copyWith(transactions: await getTransactions(activeAccount!)));
|
||||||
|
});
|
||||||
|
_beneficiariesStreamSubscription?.cancel();
|
||||||
|
_beneficiariesStreamSubscription = watchBeneficiaries().listen((_) async {
|
||||||
|
emit(state.copyWith(beneficiaries: await getBeneficiaries()));
|
||||||
|
});
|
||||||
|
_expenseCategoryStreamSubscription?.cancel();
|
||||||
|
_expenseCategoryStreamSubscription = watchExpenseCategory().listen((
|
||||||
|
_,
|
||||||
|
) async {
|
||||||
|
emit(state.copyWith(expenseCategories: await getExpenseCategories()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
final accounts = await getAccounts();
|
||||||
|
final account = accounts.isEmpty ? null : accounts[0];
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
accounts: accounts,
|
||||||
|
activeAccountIndex: accounts.isEmpty ? null : 0,
|
||||||
|
transactions: await getTransactions(account),
|
||||||
|
beneficiaries: await getBeneficiaries(),
|
||||||
|
transactionTemplates: await getTransactionTemplates(account),
|
||||||
|
recurringTransactions: await getRecurringTransactions(account),
|
||||||
|
expenseCategories: await getExpenseCategories(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (account != null) {
|
||||||
|
setupStreams(account);
|
||||||
|
} else {
|
||||||
|
setupAccountStream();
|
||||||
|
}
|
||||||
|
print("Core init done");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPage(OkanePage page) {
|
||||||
|
emit(state.copyWith(activePage: page));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setActiveAccountIndex(int index) async {
|
||||||
|
final account = state.accounts[index];
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
activeAccountIndex: index,
|
||||||
|
transactions: await getTransactions(account),
|
||||||
|
beneficiaries: await getBeneficiaries(),
|
||||||
|
transactionTemplates: await getTransactionTemplates(account),
|
||||||
|
recurringTransactions: await getRecurringTransactions(account),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setupStreams(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setActiveTransaction(Transaction? item) {
|
||||||
|
emit(state.copyWith(activeTransaction: item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAccounts(List<Account> accounts) {
|
||||||
|
emit(state.copyWith(accounts: accounts));
|
||||||
|
}
|
||||||
|
|
||||||
|
Account? get activeAccount =>
|
||||||
|
state.activeAccountIndex == null
|
||||||
|
? null
|
||||||
|
: state.accounts[state.activeAccountIndex!];
|
||||||
|
}
|
408
lib/ui/state/core.freezed.dart
Normal file
408
lib/ui/state/core.freezed.dart
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'core.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$CoreState {
|
||||||
|
OkanePage get activePage => throw _privateConstructorUsedError;
|
||||||
|
int? get activeAccountIndex => throw _privateConstructorUsedError;
|
||||||
|
Transaction? get activeTransaction => throw _privateConstructorUsedError;
|
||||||
|
List<Account> get accounts => throw _privateConstructorUsedError;
|
||||||
|
List<RecurringTransaction> get recurringTransactions =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
List<Transaction> get transactions => throw _privateConstructorUsedError;
|
||||||
|
List<TransactionTemplate> get transactionTemplates =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
List<Beneficiary> get beneficiaries => throw _privateConstructorUsedError;
|
||||||
|
List<ExpenseCategory> get expenseCategories =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$CoreStateCopyWith<CoreState> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $CoreStateCopyWith<$Res> {
|
||||||
|
factory $CoreStateCopyWith(CoreState value, $Res Function(CoreState) then) =
|
||||||
|
_$CoreStateCopyWithImpl<$Res, CoreState>;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
OkanePage activePage,
|
||||||
|
int? activeAccountIndex,
|
||||||
|
Transaction? activeTransaction,
|
||||||
|
List<Account> accounts,
|
||||||
|
List<RecurringTransaction> recurringTransactions,
|
||||||
|
List<Transaction> transactions,
|
||||||
|
List<TransactionTemplate> transactionTemplates,
|
||||||
|
List<Beneficiary> beneficiaries,
|
||||||
|
List<ExpenseCategory> expenseCategories,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$CoreStateCopyWithImpl<$Res, $Val extends CoreState>
|
||||||
|
implements $CoreStateCopyWith<$Res> {
|
||||||
|
_$CoreStateCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? activePage = null,
|
||||||
|
Object? activeAccountIndex = freezed,
|
||||||
|
Object? activeTransaction = freezed,
|
||||||
|
Object? accounts = null,
|
||||||
|
Object? recurringTransactions = null,
|
||||||
|
Object? transactions = null,
|
||||||
|
Object? transactionTemplates = null,
|
||||||
|
Object? beneficiaries = null,
|
||||||
|
Object? expenseCategories = null,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_value.copyWith(
|
||||||
|
activePage:
|
||||||
|
null == activePage
|
||||||
|
? _value.activePage
|
||||||
|
: activePage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as OkanePage,
|
||||||
|
activeAccountIndex:
|
||||||
|
freezed == activeAccountIndex
|
||||||
|
? _value.activeAccountIndex
|
||||||
|
: activeAccountIndex // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
activeTransaction:
|
||||||
|
freezed == activeTransaction
|
||||||
|
? _value.activeTransaction
|
||||||
|
: activeTransaction // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Transaction?,
|
||||||
|
accounts:
|
||||||
|
null == accounts
|
||||||
|
? _value.accounts
|
||||||
|
: accounts // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Account>,
|
||||||
|
recurringTransactions:
|
||||||
|
null == recurringTransactions
|
||||||
|
? _value.recurringTransactions
|
||||||
|
: recurringTransactions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<RecurringTransaction>,
|
||||||
|
transactions:
|
||||||
|
null == transactions
|
||||||
|
? _value.transactions
|
||||||
|
: transactions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Transaction>,
|
||||||
|
transactionTemplates:
|
||||||
|
null == transactionTemplates
|
||||||
|
? _value.transactionTemplates
|
||||||
|
: transactionTemplates // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<TransactionTemplate>,
|
||||||
|
beneficiaries:
|
||||||
|
null == beneficiaries
|
||||||
|
? _value.beneficiaries
|
||||||
|
: beneficiaries // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Beneficiary>,
|
||||||
|
expenseCategories:
|
||||||
|
null == expenseCategories
|
||||||
|
? _value.expenseCategories
|
||||||
|
: expenseCategories // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<ExpenseCategory>,
|
||||||
|
)
|
||||||
|
as $Val,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$CoreStateImplCopyWith<$Res>
|
||||||
|
implements $CoreStateCopyWith<$Res> {
|
||||||
|
factory _$$CoreStateImplCopyWith(
|
||||||
|
_$CoreStateImpl value,
|
||||||
|
$Res Function(_$CoreStateImpl) then,
|
||||||
|
) = __$$CoreStateImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
OkanePage activePage,
|
||||||
|
int? activeAccountIndex,
|
||||||
|
Transaction? activeTransaction,
|
||||||
|
List<Account> accounts,
|
||||||
|
List<RecurringTransaction> recurringTransactions,
|
||||||
|
List<Transaction> transactions,
|
||||||
|
List<TransactionTemplate> transactionTemplates,
|
||||||
|
List<Beneficiary> beneficiaries,
|
||||||
|
List<ExpenseCategory> expenseCategories,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$CoreStateImplCopyWithImpl<$Res>
|
||||||
|
extends _$CoreStateCopyWithImpl<$Res, _$CoreStateImpl>
|
||||||
|
implements _$$CoreStateImplCopyWith<$Res> {
|
||||||
|
__$$CoreStateImplCopyWithImpl(
|
||||||
|
_$CoreStateImpl _value,
|
||||||
|
$Res Function(_$CoreStateImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? activePage = null,
|
||||||
|
Object? activeAccountIndex = freezed,
|
||||||
|
Object? activeTransaction = freezed,
|
||||||
|
Object? accounts = null,
|
||||||
|
Object? recurringTransactions = null,
|
||||||
|
Object? transactions = null,
|
||||||
|
Object? transactionTemplates = null,
|
||||||
|
Object? beneficiaries = null,
|
||||||
|
Object? expenseCategories = null,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_$CoreStateImpl(
|
||||||
|
activePage:
|
||||||
|
null == activePage
|
||||||
|
? _value.activePage
|
||||||
|
: activePage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as OkanePage,
|
||||||
|
activeAccountIndex:
|
||||||
|
freezed == activeAccountIndex
|
||||||
|
? _value.activeAccountIndex
|
||||||
|
: activeAccountIndex // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
activeTransaction:
|
||||||
|
freezed == activeTransaction
|
||||||
|
? _value.activeTransaction
|
||||||
|
: activeTransaction // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Transaction?,
|
||||||
|
accounts:
|
||||||
|
null == accounts
|
||||||
|
? _value._accounts
|
||||||
|
: accounts // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Account>,
|
||||||
|
recurringTransactions:
|
||||||
|
null == recurringTransactions
|
||||||
|
? _value._recurringTransactions
|
||||||
|
: recurringTransactions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<RecurringTransaction>,
|
||||||
|
transactions:
|
||||||
|
null == transactions
|
||||||
|
? _value._transactions
|
||||||
|
: transactions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Transaction>,
|
||||||
|
transactionTemplates:
|
||||||
|
null == transactionTemplates
|
||||||
|
? _value._transactionTemplates
|
||||||
|
: transactionTemplates // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<TransactionTemplate>,
|
||||||
|
beneficiaries:
|
||||||
|
null == beneficiaries
|
||||||
|
? _value._beneficiaries
|
||||||
|
: beneficiaries // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Beneficiary>,
|
||||||
|
expenseCategories:
|
||||||
|
null == expenseCategories
|
||||||
|
? _value._expenseCategories
|
||||||
|
: expenseCategories // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<ExpenseCategory>,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$CoreStateImpl implements _CoreState {
|
||||||
|
const _$CoreStateImpl({
|
||||||
|
this.activePage = OkanePage.accounts,
|
||||||
|
this.activeAccountIndex,
|
||||||
|
this.activeTransaction = null,
|
||||||
|
final List<Account> accounts = const [],
|
||||||
|
final List<RecurringTransaction> recurringTransactions = const [],
|
||||||
|
final List<Transaction> transactions = const [],
|
||||||
|
final List<TransactionTemplate> transactionTemplates = const [],
|
||||||
|
final List<Beneficiary> beneficiaries = const [],
|
||||||
|
final List<ExpenseCategory> expenseCategories = const [],
|
||||||
|
}) : _accounts = accounts,
|
||||||
|
_recurringTransactions = recurringTransactions,
|
||||||
|
_transactions = transactions,
|
||||||
|
_transactionTemplates = transactionTemplates,
|
||||||
|
_beneficiaries = beneficiaries,
|
||||||
|
_expenseCategories = expenseCategories;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final OkanePage activePage;
|
||||||
|
@override
|
||||||
|
final int? activeAccountIndex;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final Transaction? activeTransaction;
|
||||||
|
final List<Account> _accounts;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<Account> get accounts {
|
||||||
|
if (_accounts is EqualUnmodifiableListView) return _accounts;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<RecurringTransaction> _recurringTransactions;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<RecurringTransaction> get recurringTransactions {
|
||||||
|
if (_recurringTransactions is EqualUnmodifiableListView)
|
||||||
|
return _recurringTransactions;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_recurringTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Transaction> _transactions;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<Transaction> get transactions {
|
||||||
|
if (_transactions is EqualUnmodifiableListView) return _transactions;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<TransactionTemplate> _transactionTemplates;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<TransactionTemplate> get transactionTemplates {
|
||||||
|
if (_transactionTemplates is EqualUnmodifiableListView)
|
||||||
|
return _transactionTemplates;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_transactionTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Beneficiary> _beneficiaries;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<Beneficiary> get beneficiaries {
|
||||||
|
if (_beneficiaries is EqualUnmodifiableListView) return _beneficiaries;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_beneficiaries);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<ExpenseCategory> _expenseCategories;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
List<ExpenseCategory> get expenseCategories {
|
||||||
|
if (_expenseCategories is EqualUnmodifiableListView)
|
||||||
|
return _expenseCategories;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_expenseCategories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'CoreState(activePage: $activePage, activeAccountIndex: $activeAccountIndex, activeTransaction: $activeTransaction, accounts: $accounts, recurringTransactions: $recurringTransactions, transactions: $transactions, transactionTemplates: $transactionTemplates, beneficiaries: $beneficiaries, expenseCategories: $expenseCategories)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$CoreStateImpl &&
|
||||||
|
(identical(other.activePage, activePage) ||
|
||||||
|
other.activePage == activePage) &&
|
||||||
|
(identical(other.activeAccountIndex, activeAccountIndex) ||
|
||||||
|
other.activeAccountIndex == activeAccountIndex) &&
|
||||||
|
(identical(other.activeTransaction, activeTransaction) ||
|
||||||
|
other.activeTransaction == activeTransaction) &&
|
||||||
|
const DeepCollectionEquality().equals(other._accounts, _accounts) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._recurringTransactions,
|
||||||
|
_recurringTransactions,
|
||||||
|
) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._transactions,
|
||||||
|
_transactions,
|
||||||
|
) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._transactionTemplates,
|
||||||
|
_transactionTemplates,
|
||||||
|
) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._beneficiaries,
|
||||||
|
_beneficiaries,
|
||||||
|
) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._expenseCategories,
|
||||||
|
_expenseCategories,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
activePage,
|
||||||
|
activeAccountIndex,
|
||||||
|
activeTransaction,
|
||||||
|
const DeepCollectionEquality().hash(_accounts),
|
||||||
|
const DeepCollectionEquality().hash(_recurringTransactions),
|
||||||
|
const DeepCollectionEquality().hash(_transactions),
|
||||||
|
const DeepCollectionEquality().hash(_transactionTemplates),
|
||||||
|
const DeepCollectionEquality().hash(_beneficiaries),
|
||||||
|
const DeepCollectionEquality().hash(_expenseCategories),
|
||||||
|
);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$CoreStateImplCopyWith<_$CoreStateImpl> get copyWith =>
|
||||||
|
__$$CoreStateImplCopyWithImpl<_$CoreStateImpl>(this, _$identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _CoreState implements CoreState {
|
||||||
|
const factory _CoreState({
|
||||||
|
final OkanePage activePage,
|
||||||
|
final int? activeAccountIndex,
|
||||||
|
final Transaction? activeTransaction,
|
||||||
|
final List<Account> accounts,
|
||||||
|
final List<RecurringTransaction> recurringTransactions,
|
||||||
|
final List<Transaction> transactions,
|
||||||
|
final List<TransactionTemplate> transactionTemplates,
|
||||||
|
final List<Beneficiary> beneficiaries,
|
||||||
|
final List<ExpenseCategory> expenseCategories,
|
||||||
|
}) = _$CoreStateImpl;
|
||||||
|
|
||||||
|
@override
|
||||||
|
OkanePage get activePage;
|
||||||
|
@override
|
||||||
|
int? get activeAccountIndex;
|
||||||
|
@override
|
||||||
|
Transaction? get activeTransaction;
|
||||||
|
@override
|
||||||
|
List<Account> get accounts;
|
||||||
|
@override
|
||||||
|
List<RecurringTransaction> get recurringTransactions;
|
||||||
|
@override
|
||||||
|
List<Transaction> get transactions;
|
||||||
|
@override
|
||||||
|
List<TransactionTemplate> get transactionTemplates;
|
||||||
|
@override
|
||||||
|
List<Beneficiary> get beneficiaries;
|
||||||
|
@override
|
||||||
|
List<ExpenseCategory> get expenseCategories;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$CoreStateImplCopyWith<_$CoreStateImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
1
lib/ui/transaction.dart
Normal file
1
lib/ui/transaction.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
enum TransactionDirection { send, receive }
|
71
lib/ui/utils.dart
Normal file
71
lib/ui/utils.dart
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:okane/screen.dart';
|
||||||
|
|
||||||
|
Future<T?> showDialogOrModal<T>({
|
||||||
|
required BuildContext context,
|
||||||
|
required WidgetBuilder builder,
|
||||||
|
bool showDragHandle = true,
|
||||||
|
}) {
|
||||||
|
final screenSize = getScreenSize(context);
|
||||||
|
final width = MediaQuery.sizeOf(context).shortestSide;
|
||||||
|
|
||||||
|
return switch (screenSize) {
|
||||||
|
ScreenSize.small => showModalBottomSheet<T>(
|
||||||
|
context: context,
|
||||||
|
showDragHandle: showDragHandle,
|
||||||
|
builder:
|
||||||
|
(context) => Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 32),
|
||||||
|
child: builder(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ScreenSize.normal => showDialog<T>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => Dialog(
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: width * 0.7),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 32),
|
||||||
|
child: builder(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime toMidnight(DateTime t) {
|
||||||
|
return DateTime(t.year, t.month, t.day);
|
||||||
|
}
|
||||||
|
|
||||||
|
String zeroPad(int i) {
|
||||||
|
if (i <= 9) {
|
||||||
|
return "0$i";
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatDateTime(DateTime dt, {bool formatYear = true}) {
|
||||||
|
if (!formatYear) {
|
||||||
|
return "${zeroPad(dt.day)}.${zeroPad(dt.month)}";
|
||||||
|
}
|
||||||
|
return "${zeroPad(dt.day)}.${zeroPad(dt.month)}.${zeroPad(dt.year)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
Color colorHash(String text) {
|
||||||
|
final hue =
|
||||||
|
text.characters
|
||||||
|
.map((c) => c.codeUnitAt(0).toDouble())
|
||||||
|
.reduce((acc, c) => c + ((acc.toInt() << 5) - acc)) %
|
||||||
|
360;
|
||||||
|
return HSVColor.fromAHSV(1, hue, 0.5, 0.5).toColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatCurrency(double amount, {bool precise = true}) {
|
||||||
|
if (!precise) {
|
||||||
|
return "${amount.toInt()}€";
|
||||||
|
}
|
||||||
|
return "${amount.toStringAsFixed(2)}€";
|
||||||
|
}
|
66
lib/ui/widgets/add_expense_category.dart
Normal file
66
lib/ui/widgets/add_expense_category.dart
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
|
||||||
|
class AddExpenseCategory extends StatefulWidget {
|
||||||
|
const AddExpenseCategory({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
AddExpenseCategoryState createState() => AddExpenseCategoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddExpenseCategoryState extends State<AddExpenseCategory> {
|
||||||
|
final TextEditingController _categoryNameController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxHeight: 300),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListView.builder(
|
||||||
|
itemCount: state.expenseCategories.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder:
|
||||||
|
(context, index) => ListTile(
|
||||||
|
title: Text(state.expenseCategories[index].name),
|
||||||
|
onTap: () {
|
||||||
|
_categoryNameController.text = "";
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pop(state.expenseCategories[index]);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
decoration: InputDecoration(hintText: "Category name"),
|
||||||
|
controller: _categoryNameController,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final category =
|
||||||
|
ExpenseCategory()
|
||||||
|
..name = _categoryNameController.text;
|
||||||
|
await upsertExpenseCategory(category);
|
||||||
|
_categoryNameController.text = "";
|
||||||
|
Navigator.of(context).pop(category);
|
||||||
|
},
|
||||||
|
child: Text("Add"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
284
lib/ui/widgets/add_recurring_transaction.dart
Normal file
284
lib/ui/widgets/add_recurring_transaction.dart
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_picker_plus/picker.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/recurrent.dart';
|
||||||
|
import 'package:okane/database/collections/template.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/transaction.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:searchfield/searchfield.dart';
|
||||||
|
|
||||||
|
enum Period { days, weeks, months, years }
|
||||||
|
|
||||||
|
class AddRecurringTransactionTemplateWidget extends StatefulWidget {
|
||||||
|
final VoidCallback onAdd;
|
||||||
|
|
||||||
|
final Account activeAccountItem;
|
||||||
|
|
||||||
|
const AddRecurringTransactionTemplateWidget({
|
||||||
|
super.key,
|
||||||
|
required this.activeAccountItem,
|
||||||
|
required this.onAdd,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddRecurringTransactionTemplateWidget> createState() =>
|
||||||
|
_AddRecurringTransactionTemplateWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddRecurringTransactionTemplateWidgetState
|
||||||
|
extends State<AddRecurringTransactionTemplateWidget> {
|
||||||
|
final TextEditingController _beneficiaryTextController =
|
||||||
|
TextEditingController();
|
||||||
|
final TextEditingController _amountTextController = TextEditingController();
|
||||||
|
final TextEditingController _templateNameController = TextEditingController();
|
||||||
|
|
||||||
|
List<Beneficiary> beneficiaries = [];
|
||||||
|
|
||||||
|
SearchFieldListItem<Beneficiary>? _selectedBeneficiary;
|
||||||
|
|
||||||
|
TransactionDirection _selectedDirection = TransactionDirection.send;
|
||||||
|
|
||||||
|
Period _selectedPeriod = Period.months;
|
||||||
|
int _periodSize = 1;
|
||||||
|
|
||||||
|
String getBeneficiaryName(Beneficiary item) {
|
||||||
|
return switch (item.type) {
|
||||||
|
BeneficiaryType.account => "${item.name} (Account)",
|
||||||
|
BeneficiaryType.other => item.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _submit(BuildContext context) async {
|
||||||
|
final beneficiaryName = _beneficiaryTextController.text;
|
||||||
|
if (_selectedBeneficiary == null && beneficiaryName.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_templateNameController.text.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Beneficiary? beneficiary = _selectedBeneficiary?.item;
|
||||||
|
if (beneficiary == null ||
|
||||||
|
getBeneficiaryName(beneficiary) != beneficiaryName) {
|
||||||
|
// Add a new beneficiary, if none was selected
|
||||||
|
final result = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
|
title: const Text("Add Beneficiary"),
|
||||||
|
content: Text(
|
||||||
|
"The beneficiary '$beneficiaryName' does not exist. Do you want to add it?",
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Add'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result == null || !result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
beneficiary =
|
||||||
|
Beneficiary()
|
||||||
|
..name = beneficiaryName
|
||||||
|
..type = BeneficiaryType.other;
|
||||||
|
await upsertBeneficiary(beneficiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
final days = switch (_selectedPeriod) {
|
||||||
|
Period.days => _periodSize,
|
||||||
|
Period.weeks => _periodSize * 7,
|
||||||
|
Period.months => _periodSize * 31,
|
||||||
|
Period.years => _periodSize * 365,
|
||||||
|
};
|
||||||
|
final factor = switch (_selectedDirection) {
|
||||||
|
TransactionDirection.send => -1,
|
||||||
|
TransactionDirection.receive => 1,
|
||||||
|
};
|
||||||
|
final amount = factor * double.parse(_amountTextController.text).abs();
|
||||||
|
final template =
|
||||||
|
TransactionTemplate()
|
||||||
|
..name = _templateNameController.text
|
||||||
|
..beneficiary.value = beneficiary
|
||||||
|
..account.value = widget.activeAccountItem
|
||||||
|
..recurring = true
|
||||||
|
..amount = amount;
|
||||||
|
await upsertTransactionTemplate(template);
|
||||||
|
|
||||||
|
final transaction =
|
||||||
|
RecurringTransaction()
|
||||||
|
..lastExecution = null
|
||||||
|
..template.value = template
|
||||||
|
..account.value = widget.activeAccountItem
|
||||||
|
..days = days;
|
||||||
|
await upsertRecurringTransaction(transaction);
|
||||||
|
|
||||||
|
_periodSize = 1;
|
||||||
|
_selectedPeriod = Period.weeks;
|
||||||
|
_amountTextController.text = "";
|
||||||
|
_templateNameController.text = "";
|
||||||
|
widget.onAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: TextField(
|
||||||
|
controller: _templateNameController,
|
||||||
|
decoration: InputDecoration(label: Text("Template name")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: SearchField<Beneficiary>(
|
||||||
|
suggestions:
|
||||||
|
beneficiaries
|
||||||
|
.where((el) {
|
||||||
|
final bloc = GetIt.I.get<CoreCubit>();
|
||||||
|
if (el.type == BeneficiaryType.account) {
|
||||||
|
return el.account.value?.id != bloc.activeAccount?.id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((el) {
|
||||||
|
return SearchFieldListItem(
|
||||||
|
getBeneficiaryName(el),
|
||||||
|
item: el,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
|
hint: "Beneficiary",
|
||||||
|
controller: _beneficiaryTextController,
|
||||||
|
selectedValue: _selectedBeneficiary,
|
||||||
|
onSuggestionTap: (beneficiary) {
|
||||||
|
setState(() => _selectedBeneficiary = beneficiary);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: TextField(
|
||||||
|
controller: _amountTextController,
|
||||||
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
|
signed: false,
|
||||||
|
decimal: false,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(hintText: "Amount"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: SegmentedButton<TransactionDirection>(
|
||||||
|
segments: [
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.send,
|
||||||
|
label: Text("Send"),
|
||||||
|
icon: Icon(Icons.remove),
|
||||||
|
),
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.receive,
|
||||||
|
label: Text("Receive"),
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
selected: <TransactionDirection>{_selectedDirection},
|
||||||
|
multiSelectionEnabled: false,
|
||||||
|
onSelectionChanged: (selection) {
|
||||||
|
setState(() => _selectedDirection = selection.first);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||||
|
child: SegmentedButton<Period>(
|
||||||
|
segments: [
|
||||||
|
ButtonSegment(value: Period.days, label: Text("Days")),
|
||||||
|
ButtonSegment(value: Period.weeks, label: Text("Weeks")),
|
||||||
|
ButtonSegment(value: Period.months, label: Text("Months")),
|
||||||
|
ButtonSegment(value: Period.years, label: Text("Years")),
|
||||||
|
],
|
||||||
|
selected: <Period>{_selectedPeriod},
|
||||||
|
multiSelectionEnabled: false,
|
||||||
|
onSelectionChanged: (selection) {
|
||||||
|
setState(() => _selectedPeriod = selection.first);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: "Repeat every ",
|
||||||
|
children: [
|
||||||
|
WidgetSpan(
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Picker(
|
||||||
|
adapter: NumberPickerAdapter(
|
||||||
|
data: [
|
||||||
|
NumberPickerColumn(
|
||||||
|
begin: 1,
|
||||||
|
end: 999,
|
||||||
|
initValue: _periodSize,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
hideHeader: true,
|
||||||
|
selectedTextStyle: TextStyle(color: Colors.blue),
|
||||||
|
onConfirm: (Picker picker, List value) {
|
||||||
|
setState(() {
|
||||||
|
_periodSize = (value.first as int) + 1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
).showDialog(context);
|
||||||
|
},
|
||||||
|
child: Text(_periodSize.toString()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: switch (_selectedPeriod) {
|
||||||
|
Period.days => " days",
|
||||||
|
Period.weeks => " weeks",
|
||||||
|
Period.months => " months",
|
||||||
|
Period.years => " years",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: OutlinedButton(
|
||||||
|
onPressed: () => _submit(context),
|
||||||
|
child: Text("Add"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
229
lib/ui/widgets/add_template.dart
Normal file
229
lib/ui/widgets/add_template.dart
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
import 'package:okane/database/collections/template.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/transaction.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/add_expense_category.dart';
|
||||||
|
import 'package:searchfield/searchfield.dart';
|
||||||
|
|
||||||
|
class AddTransactionTemplateWidget extends StatefulWidget {
|
||||||
|
final VoidCallback onAdd;
|
||||||
|
|
||||||
|
final Account activeAccountItem;
|
||||||
|
|
||||||
|
const AddTransactionTemplateWidget({
|
||||||
|
super.key,
|
||||||
|
required this.activeAccountItem,
|
||||||
|
required this.onAdd,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddTransactionTemplateWidget> createState() =>
|
||||||
|
_AddTransactionTemplateWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddTransactionTemplateWidgetState
|
||||||
|
extends State<AddTransactionTemplateWidget> {
|
||||||
|
final TextEditingController _beneficiaryTextController =
|
||||||
|
TextEditingController();
|
||||||
|
final TextEditingController _amountTextController = TextEditingController();
|
||||||
|
final TextEditingController _templateNameController = TextEditingController();
|
||||||
|
|
||||||
|
SearchFieldListItem<Beneficiary>? _selectedBeneficiary;
|
||||||
|
|
||||||
|
TransactionDirection _selectedDirection = TransactionDirection.send;
|
||||||
|
|
||||||
|
ExpenseCategory? _expenseCategory = null;
|
||||||
|
|
||||||
|
String getBeneficiaryName(Beneficiary item) {
|
||||||
|
return switch (item.type) {
|
||||||
|
BeneficiaryType.account => "${item.name} (Account)",
|
||||||
|
BeneficiaryType.other => item.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _submit(BuildContext context) async {
|
||||||
|
final beneficiaryName = _beneficiaryTextController.text;
|
||||||
|
if (_selectedBeneficiary == null && beneficiaryName.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_templateNameController.text.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Beneficiary? beneficiary = _selectedBeneficiary?.item;
|
||||||
|
if (beneficiary == null ||
|
||||||
|
getBeneficiaryName(beneficiary) != beneficiaryName) {
|
||||||
|
// Add a new beneficiary, if none was selected
|
||||||
|
final result = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
|
title: const Text("Add Beneficiary"),
|
||||||
|
content: Text(
|
||||||
|
"The beneficiary '$beneficiaryName' does not exist. Do you want to add it?",
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Add'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result == null || !result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
beneficiary =
|
||||||
|
Beneficiary()
|
||||||
|
..name = beneficiaryName
|
||||||
|
..type = BeneficiaryType.other;
|
||||||
|
await upsertBeneficiary(beneficiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
final factor = switch (_selectedDirection) {
|
||||||
|
TransactionDirection.send => -1,
|
||||||
|
TransactionDirection.receive => 1,
|
||||||
|
};
|
||||||
|
final amount = factor * double.parse(_amountTextController.text).abs();
|
||||||
|
final transaction =
|
||||||
|
TransactionTemplate()
|
||||||
|
..name = _templateNameController.text
|
||||||
|
..account.value = widget.activeAccountItem
|
||||||
|
..beneficiary.value = beneficiary
|
||||||
|
..expenseCategory.value = _expenseCategory
|
||||||
|
..recurring = false
|
||||||
|
..amount = amount;
|
||||||
|
await upsertTransactionTemplate(transaction);
|
||||||
|
widget.onAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: TextField(
|
||||||
|
controller: _templateNameController,
|
||||||
|
decoration: InputDecoration(label: Text("Template name")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => SearchField<Beneficiary>(
|
||||||
|
suggestions:
|
||||||
|
state.beneficiaries
|
||||||
|
.where((el) {
|
||||||
|
final bloc = GetIt.I.get<CoreCubit>();
|
||||||
|
if (el.type == BeneficiaryType.account) {
|
||||||
|
return el.account.value?.id !=
|
||||||
|
bloc.activeAccount?.id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((el) {
|
||||||
|
return SearchFieldListItem(
|
||||||
|
getBeneficiaryName(el),
|
||||||
|
item: el,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
|
hint: "Beneficiary",
|
||||||
|
controller: _beneficiaryTextController,
|
||||||
|
selectedValue: _selectedBeneficiary,
|
||||||
|
onSuggestionTap: (beneficiary) {
|
||||||
|
setState(() => _selectedBeneficiary = beneficiary);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: TextField(
|
||||||
|
controller: _amountTextController,
|
||||||
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
|
signed: false,
|
||||||
|
decimal: false,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(hintText: "Amount"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("Expense category"),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final category = await showDialogOrModal(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => AddExpenseCategory(),
|
||||||
|
);
|
||||||
|
if (category == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _expenseCategory = category);
|
||||||
|
},
|
||||||
|
child: Text(_expenseCategory?.name ?? "None"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: SegmentedButton<TransactionDirection>(
|
||||||
|
segments: [
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.send,
|
||||||
|
label: Text("Send"),
|
||||||
|
icon: Icon(Icons.remove),
|
||||||
|
),
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.receive,
|
||||||
|
label: Text("Receive"),
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
selected: <TransactionDirection>{_selectedDirection},
|
||||||
|
multiSelectionEnabled: false,
|
||||||
|
onSelectionChanged: (selection) {
|
||||||
|
setState(() => _selectedDirection = selection.first);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: OutlinedButton(
|
||||||
|
onPressed: () => _submit(context),
|
||||||
|
child: Text("Add"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
311
lib/ui/widgets/add_transaction.dart
Normal file
311
lib/ui/widgets/add_transaction.dart
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:okane/database/collections/account.dart';
|
||||||
|
import 'package:okane/database/collections/beneficiary.dart';
|
||||||
|
import 'package:okane/database/collections/expense_category.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/state/core.dart';
|
||||||
|
import 'package:okane/ui/transaction.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/add_expense_category.dart';
|
||||||
|
import 'package:searchfield/searchfield.dart';
|
||||||
|
|
||||||
|
class AddTransactionWidget extends StatefulWidget {
|
||||||
|
final VoidCallback onAdd;
|
||||||
|
|
||||||
|
final Account activeAccountItem;
|
||||||
|
|
||||||
|
const AddTransactionWidget({
|
||||||
|
super.key,
|
||||||
|
required this.activeAccountItem,
|
||||||
|
required this.onAdd,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddTransactionWidget> createState() => _AddTransactionWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddTransactionWidgetState extends State<AddTransactionWidget> {
|
||||||
|
final TextEditingController _beneficiaryTextController =
|
||||||
|
TextEditingController();
|
||||||
|
final TextEditingController _amountTextController = TextEditingController();
|
||||||
|
|
||||||
|
DateTime _selectedDate = DateTime.now();
|
||||||
|
|
||||||
|
SearchFieldListItem<Beneficiary>? _selectedBeneficiary;
|
||||||
|
|
||||||
|
TransactionDirection _selectedDirection = TransactionDirection.send;
|
||||||
|
|
||||||
|
ExpenseCategory? _expenseCategory = null;
|
||||||
|
|
||||||
|
String getBeneficiaryName(Beneficiary item) {
|
||||||
|
return switch (item.type) {
|
||||||
|
BeneficiaryType.account => "${item.name} (Account)",
|
||||||
|
BeneficiaryType.other => item.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _submit(BuildContext context) async {
|
||||||
|
final beneficiaryName = _beneficiaryTextController.text;
|
||||||
|
if (_selectedBeneficiary == null && beneficiaryName.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Beneficiary? beneficiary = _selectedBeneficiary?.item;
|
||||||
|
if (beneficiary == null ||
|
||||||
|
getBeneficiaryName(beneficiary) != beneficiaryName) {
|
||||||
|
// Add a new beneficiary, if none was selected
|
||||||
|
final result = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
|
title: const Text("Add Beneficiary"),
|
||||||
|
content: Text(
|
||||||
|
"The beneficiary '$beneficiaryName' does not exist. Do you want to add it?",
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Add'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result == null || !result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
beneficiary =
|
||||||
|
Beneficiary()
|
||||||
|
..name = beneficiaryName
|
||||||
|
..type = BeneficiaryType.other;
|
||||||
|
await upsertBeneficiary(beneficiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
final factor = switch (_selectedDirection) {
|
||||||
|
TransactionDirection.send => -1,
|
||||||
|
TransactionDirection.receive => 1,
|
||||||
|
};
|
||||||
|
final amount = factor * double.parse(_amountTextController.text).abs();
|
||||||
|
final transaction =
|
||||||
|
Transaction()
|
||||||
|
..account.value = widget.activeAccountItem
|
||||||
|
..beneficiary.value = beneficiary
|
||||||
|
..amount = amount
|
||||||
|
..tags = []
|
||||||
|
..expenseCategory.value = _expenseCategory
|
||||||
|
..date = _selectedDate;
|
||||||
|
await upsertTransaction(transaction);
|
||||||
|
|
||||||
|
if (beneficiary.type == BeneficiaryType.account) {
|
||||||
|
final otherTransaction =
|
||||||
|
Transaction()
|
||||||
|
..account.value = beneficiary.account.value!
|
||||||
|
..beneficiary.value = await getAccountBeneficiary(
|
||||||
|
widget.activeAccountItem,
|
||||||
|
)
|
||||||
|
..date = _selectedDate
|
||||||
|
..expenseCategory.value = _expenseCategory
|
||||||
|
..amount = -1 * amount;
|
||||||
|
await upsertTransaction(otherTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.onAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: [
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final template = await showDialogOrModal<Transaction>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state.transactionTemplates.isEmpty) {
|
||||||
|
return Text("No templates defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: state.transactionTemplates.length,
|
||||||
|
itemBuilder:
|
||||||
|
(context, index) => ListTile(
|
||||||
|
title: Text(
|
||||||
|
state.transactionTemplates[index].name,
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pop(state.transactionTemplates[index]);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (template == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_amountTextController.text = template.amount.toString();
|
||||||
|
_selectedDirection =
|
||||||
|
template.amount > 0
|
||||||
|
? TransactionDirection.receive
|
||||||
|
: TransactionDirection.send;
|
||||||
|
_selectedBeneficiary = SearchFieldListItem(
|
||||||
|
getBeneficiaryName(template.beneficiary.value!),
|
||||||
|
item: template.beneficiary.value!,
|
||||||
|
);
|
||||||
|
_beneficiaryTextController.text = getBeneficiaryName(
|
||||||
|
template.beneficiary.value!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text("Use template"),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: BlocBuilder<CoreCubit, CoreState>(
|
||||||
|
builder:
|
||||||
|
(context, state) => SearchField<Beneficiary>(
|
||||||
|
suggestions:
|
||||||
|
state.beneficiaries
|
||||||
|
.where((el) {
|
||||||
|
final bloc = GetIt.I.get<CoreCubit>();
|
||||||
|
if (el.type == BeneficiaryType.account) {
|
||||||
|
return el.account.value?.id.toInt() ==
|
||||||
|
bloc.activeAccount?.id.toInt();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((el) {
|
||||||
|
return SearchFieldListItem(
|
||||||
|
getBeneficiaryName(el),
|
||||||
|
item: el,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
|
hint: "Beneficiary",
|
||||||
|
controller: _beneficiaryTextController,
|
||||||
|
selectedValue: _selectedBeneficiary,
|
||||||
|
onSuggestionTap: (beneficiary) {
|
||||||
|
setState(() => _selectedBeneficiary = beneficiary);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: TextField(
|
||||||
|
controller: _amountTextController,
|
||||||
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
|
signed: false,
|
||||||
|
decimal: false,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(hintText: "Amount"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Date"),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final dt = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: _selectedDate,
|
||||||
|
firstDate: DateTime(1),
|
||||||
|
lastDate: DateTime(9999),
|
||||||
|
);
|
||||||
|
if (dt == null) return;
|
||||||
|
|
||||||
|
setState(() => _selectedDate = dt);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.date_range),
|
||||||
|
Text(formatDateTime(_selectedDate)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("Expense category"),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final category = await showDialogOrModal(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => AddExpenseCategory(),
|
||||||
|
);
|
||||||
|
if (category == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _expenseCategory = category);
|
||||||
|
},
|
||||||
|
child: Text(_expenseCategory?.name ?? "None"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: SegmentedButton<TransactionDirection>(
|
||||||
|
segments: [
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.send,
|
||||||
|
label: Text("Send"),
|
||||||
|
icon: Icon(Icons.remove),
|
||||||
|
),
|
||||||
|
ButtonSegment(
|
||||||
|
value: TransactionDirection.receive,
|
||||||
|
label: Text("Receive"),
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
selected: <TransactionDirection>{_selectedDirection},
|
||||||
|
multiSelectionEnabled: false,
|
||||||
|
onSelectionChanged: (selection) {
|
||||||
|
setState(() => _selectedDirection = selection.first);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: OutlinedButton(
|
||||||
|
onPressed: () => _submit(context),
|
||||||
|
child: Text("Add"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
40
lib/ui/widgets/image_wrapper.dart
Normal file
40
lib/ui/widgets/image_wrapper.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ImageWrapper extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String? path;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
const ImageWrapper({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.onTap,
|
||||||
|
this.path,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Widget widget;
|
||||||
|
if (path == null) {
|
||||||
|
widget = SizedBox(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Center(child: Text(title[0])),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
widget = ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Image.file(File(path!), width: 45, height: 45),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InkWell(onTap: onTap, child: widget);
|
||||||
|
}
|
||||||
|
}
|
49
lib/ui/widgets/transaction_card.dart
Normal file
49
lib/ui/widgets/transaction_card.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:okane/database/collections/transaction.dart';
|
||||||
|
import 'package:okane/database/database.dart';
|
||||||
|
import 'package:okane/ui/utils.dart';
|
||||||
|
import 'package:okane/ui/widgets/image_wrapper.dart';
|
||||||
|
|
||||||
|
class TransactionCard extends StatelessWidget {
|
||||||
|
final Widget? subtitle;
|
||||||
|
|
||||||
|
const TransactionCard({
|
||||||
|
super.key,
|
||||||
|
required this.transaction,
|
||||||
|
required this.onTap,
|
||||||
|
this.subtitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Transaction transaction;
|
||||||
|
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: ListTile(
|
||||||
|
onTap: onTap,
|
||||||
|
leading: ImageWrapper(
|
||||||
|
title: transaction.beneficiary.value!.name,
|
||||||
|
path: transaction.beneficiary.value!.imagePath,
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
trailing: Text(formatDateTime(transaction.date)),
|
||||||
|
title: Text(transaction.beneficiary.value!.name),
|
||||||
|
subtitle: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
formatCurrency(transaction.amount),
|
||||||
|
style: TextStyle(
|
||||||
|
color: transaction.amount < 0 ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (subtitle != null) subtitle!,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
1
linux/.gitignore
vendored
Normal file
1
linux/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
flutter/ephemeral
|
128
linux/CMakeLists.txt
Normal file
128
linux/CMakeLists.txt
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Project-level configuration.
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
|
# The name of the executable created for the application. Change this to change
|
||||||
|
# the on-disk name of your application.
|
||||||
|
set(BINARY_NAME "okane")
|
||||||
|
# The unique GTK application identifier for this application. See:
|
||||||
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
|
set(APPLICATION_ID "com.example.okane")
|
||||||
|
|
||||||
|
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||||
|
# versions of CMake.
|
||||||
|
cmake_policy(SET CMP0063 NEW)
|
||||||
|
|
||||||
|
# Load bundled libraries from the lib/ directory relative to the binary.
|
||||||
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||||
|
|
||||||
|
# Root filesystem for cross-building.
|
||||||
|
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||||
|
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||||
|
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Define build configuration options.
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||||
|
STRING "Flutter build mode" FORCE)
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||||
|
"Debug" "Profile" "Release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compilation settings that should be applied to most targets.
|
||||||
|
#
|
||||||
|
# Be cautious about adding new options here, as plugins use this function by
|
||||||
|
# default. In most cases, you should add new options to specific targets instead
|
||||||
|
# of modifying this function.
|
||||||
|
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||||
|
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||||
|
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||||
|
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||||
|
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Flutter library and tool build rules.
|
||||||
|
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||||
|
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||||
|
|
||||||
|
# System-level dependencies.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
|
||||||
|
# Application build; see runner/CMakeLists.txt.
|
||||||
|
add_subdirectory("runner")
|
||||||
|
|
||||||
|
# Run the Flutter tool portions of the build. This must not be removed.
|
||||||
|
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||||
|
|
||||||
|
# Only the install-generated bundle's copy of the executable will launch
|
||||||
|
# correctly, since the resources must in the right relative locations. To avoid
|
||||||
|
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
||||||
|
# the default top-level location.
|
||||||
|
set_target_properties(${BINARY_NAME}
|
||||||
|
PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Generated plugin build rules, which manage building the plugins and adding
|
||||||
|
# them to the application.
|
||||||
|
include(flutter/generated_plugins.cmake)
|
||||||
|
|
||||||
|
|
||||||
|
# === Installation ===
|
||||||
|
# By default, "installing" just makes a relocatable bundle in the build
|
||||||
|
# directory.
|
||||||
|
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||||
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||||
|
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Start with a clean build bundle directory every time.
|
||||||
|
install(CODE "
|
||||||
|
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
||||||
|
" COMPONENT Runtime)
|
||||||
|
|
||||||
|
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||||
|
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
|
|
||||||
|
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||||
|
install(FILES "${bundled_library}"
|
||||||
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
endforeach(bundled_library)
|
||||||
|
|
||||||
|
# Copy the native assets provided by the build.dart from all packages.
|
||||||
|
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
|
||||||
|
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
||||||
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||||
|
# from a previous install.
|
||||||
|
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||||
|
install(CODE "
|
||||||
|
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||||
|
" COMPONENT Runtime)
|
||||||
|
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||||
|
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||||
|
|
||||||
|
# Install the AOT library on non-Debug builds only.
|
||||||
|
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
|
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
endif()
|
88
linux/flutter/CMakeLists.txt
Normal file
88
linux/flutter/CMakeLists.txt
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# This file controls Flutter-level build steps. It should not be edited.
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||||
|
|
||||||
|
# Configuration provided via flutter tool.
|
||||||
|
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||||
|
|
||||||
|
# TODO: Move the rest of this into files in ephemeral. See
|
||||||
|
# https://github.com/flutter/flutter/issues/57146.
|
||||||
|
|
||||||
|
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
||||||
|
# which isn't available in 3.10.
|
||||||
|
function(list_prepend LIST_NAME PREFIX)
|
||||||
|
set(NEW_LIST "")
|
||||||
|
foreach(element ${${LIST_NAME}})
|
||||||
|
list(APPEND NEW_LIST "${PREFIX}${element}")
|
||||||
|
endforeach(element)
|
||||||
|
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# === Flutter Library ===
|
||||||
|
# System-level dependencies.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||||
|
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
||||||
|
|
||||||
|
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
|
||||||
|
|
||||||
|
# Published to parent scope for install step.
|
||||||
|
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||||
|
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||||
|
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
||||||
|
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||||
|
"fl_basic_message_channel.h"
|
||||||
|
"fl_binary_codec.h"
|
||||||
|
"fl_binary_messenger.h"
|
||||||
|
"fl_dart_project.h"
|
||||||
|
"fl_engine.h"
|
||||||
|
"fl_json_message_codec.h"
|
||||||
|
"fl_json_method_codec.h"
|
||||||
|
"fl_message_codec.h"
|
||||||
|
"fl_method_call.h"
|
||||||
|
"fl_method_channel.h"
|
||||||
|
"fl_method_codec.h"
|
||||||
|
"fl_method_response.h"
|
||||||
|
"fl_plugin_registrar.h"
|
||||||
|
"fl_plugin_registry.h"
|
||||||
|
"fl_standard_message_codec.h"
|
||||||
|
"fl_standard_method_codec.h"
|
||||||
|
"fl_string_codec.h"
|
||||||
|
"fl_value.h"
|
||||||
|
"fl_view.h"
|
||||||
|
"flutter_linux.h"
|
||||||
|
)
|
||||||
|
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
|
||||||
|
add_library(flutter INTERFACE)
|
||||||
|
target_include_directories(flutter INTERFACE
|
||||||
|
"${EPHEMERAL_DIR}"
|
||||||
|
)
|
||||||
|
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
||||||
|
target_link_libraries(flutter INTERFACE
|
||||||
|
PkgConfig::GTK
|
||||||
|
PkgConfig::GLIB
|
||||||
|
PkgConfig::GIO
|
||||||
|
)
|
||||||
|
add_dependencies(flutter flutter_assemble)
|
||||||
|
|
||||||
|
# === Flutter tool backend ===
|
||||||
|
# _phony_ is a non-existent file to force this command to run every time,
|
||||||
|
# since currently there's no way to get a full input/output list from the
|
||||||
|
# flutter tool.
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/_phony_
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
${FLUTTER_TOOL_ENVIRONMENT}
|
||||||
|
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
|
||||||
|
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_target(flutter_assemble DEPENDS
|
||||||
|
"${FLUTTER_LIBRARY}"
|
||||||
|
${FLUTTER_LIBRARY_HEADERS}
|
||||||
|
)
|
15
linux/flutter/generated_plugin_registrant.cc
Normal file
15
linux/flutter/generated_plugin_registrant.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||||
|
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin");
|
||||||
|
isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar);
|
||||||
|
}
|
15
linux/flutter/generated_plugin_registrant.h
Normal file
15
linux/flutter/generated_plugin_registrant.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
#define GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
|
||||||
|
// Registers Flutter plugins.
|
||||||
|
void fl_register_plugins(FlPluginRegistry* registry);
|
||||||
|
|
||||||
|
#endif // GENERATED_PLUGIN_REGISTRANT_
|
24
linux/flutter/generated_plugins.cmake
Normal file
24
linux/flutter/generated_plugins.cmake
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#
|
||||||
|
# Generated file, do not edit.
|
||||||
|
#
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
isar_flutter_libs
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|
||||||
|
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||||
|
endforeach(plugin)
|
||||||
|
|
||||||
|
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||||
|
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
||||||
|
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||||
|
endforeach(ffi_plugin)
|
26
linux/runner/CMakeLists.txt
Normal file
26
linux/runner/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Define the application target. To change its name, change BINARY_NAME in the
|
||||||
|
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
|
||||||
|
# work.
|
||||||
|
#
|
||||||
|
# Any new source files that you add to the application should be added here.
|
||||||
|
add_executable(${BINARY_NAME}
|
||||||
|
"main.cc"
|
||||||
|
"my_application.cc"
|
||||||
|
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply the standard set of build settings. This can be removed for applications
|
||||||
|
# that need different build settings.
|
||||||
|
apply_standard_settings(${BINARY_NAME})
|
||||||
|
|
||||||
|
# Add preprocessor definitions for the application ID.
|
||||||
|
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||||
|
|
||||||
|
# Add dependency libraries. Add any application-specific dependencies here.
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||||
|
|
||||||
|
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
6
linux/runner/main.cc
Normal file
6
linux/runner/main.cc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "my_application.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
g_autoptr(MyApplication) app = my_application_new();
|
||||||
|
return g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
|
}
|
130
linux/runner/my_application.cc
Normal file
130
linux/runner/my_application.cc
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "my_application.h"
|
||||||
|
|
||||||
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
#ifdef GDK_WINDOWING_X11
|
||||||
|
#include <gdk/gdkx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
struct _MyApplication {
|
||||||
|
GtkApplication parent_instance;
|
||||||
|
char** dart_entrypoint_arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
// Implements GApplication::activate.
|
||||||
|
static void my_application_activate(GApplication* application) {
|
||||||
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
|
GtkWindow* window =
|
||||||
|
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||||
|
|
||||||
|
// Use a header bar when running in GNOME as this is the common style used
|
||||||
|
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||||
|
// desktop).
|
||||||
|
// If running on X and not using GNOME then just use a traditional title bar
|
||||||
|
// in case the window manager does more exotic layout, e.g. tiling.
|
||||||
|
// If running on Wayland assume the header bar will work (may need changing
|
||||||
|
// if future cases occur).
|
||||||
|
gboolean use_header_bar = TRUE;
|
||||||
|
#ifdef GDK_WINDOWING_X11
|
||||||
|
GdkScreen* screen = gtk_window_get_screen(window);
|
||||||
|
if (GDK_IS_X11_SCREEN(screen)) {
|
||||||
|
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
|
||||||
|
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
|
||||||
|
use_header_bar = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (use_header_bar) {
|
||||||
|
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||||
|
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||||
|
gtk_header_bar_set_title(header_bar, "okane");
|
||||||
|
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||||
|
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||||
|
} else {
|
||||||
|
gtk_window_set_title(window, "okane");
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_window_set_default_size(window, 1280, 720);
|
||||||
|
gtk_widget_show(GTK_WIDGET(window));
|
||||||
|
|
||||||
|
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||||
|
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
|
||||||
|
|
||||||
|
FlView* view = fl_view_new(project);
|
||||||
|
gtk_widget_show(GTK_WIDGET(view));
|
||||||
|
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||||
|
|
||||||
|
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||||
|
|
||||||
|
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GApplication::local_command_line.
|
||||||
|
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
|
||||||
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
|
// Strip out the first argument as it is the binary name.
|
||||||
|
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
||||||
|
|
||||||
|
g_autoptr(GError) error = nullptr;
|
||||||
|
if (!g_application_register(application, nullptr, &error)) {
|
||||||
|
g_warning("Failed to register: %s", error->message);
|
||||||
|
*exit_status = 1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_application_activate(application);
|
||||||
|
*exit_status = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GApplication::startup.
|
||||||
|
static void my_application_startup(GApplication* application) {
|
||||||
|
//MyApplication* self = MY_APPLICATION(object);
|
||||||
|
|
||||||
|
// Perform any actions required at application startup.
|
||||||
|
|
||||||
|
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GApplication::shutdown.
|
||||||
|
static void my_application_shutdown(GApplication* application) {
|
||||||
|
//MyApplication* self = MY_APPLICATION(object);
|
||||||
|
|
||||||
|
// Perform any actions required at application shutdown.
|
||||||
|
|
||||||
|
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements GObject::dispose.
|
||||||
|
static void my_application_dispose(GObject* object) {
|
||||||
|
MyApplication* self = MY_APPLICATION(object);
|
||||||
|
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
|
||||||
|
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_application_class_init(MyApplicationClass* klass) {
|
||||||
|
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||||
|
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||||
|
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||||
|
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||||
|
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void my_application_init(MyApplication* self) {}
|
||||||
|
|
||||||
|
MyApplication* my_application_new() {
|
||||||
|
// Set the program name to the application ID, which helps various systems
|
||||||
|
// like GTK and desktop environments map this running application to its
|
||||||
|
// corresponding .desktop file. This ensures better integration by allowing
|
||||||
|
// the application to be recognized beyond its binary name.
|
||||||
|
g_set_prgname(APPLICATION_ID);
|
||||||
|
|
||||||
|
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||||
|
"application-id", APPLICATION_ID,
|
||||||
|
"flags", G_APPLICATION_NON_UNIQUE,
|
||||||
|
nullptr));
|
||||||
|
}
|
18
linux/runner/my_application.h
Normal file
18
linux/runner/my_application.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef FLUTTER_MY_APPLICATION_H_
|
||||||
|
#define FLUTTER_MY_APPLICATION_H_
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
|
||||||
|
GtkApplication)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* my_application_new:
|
||||||
|
*
|
||||||
|
* Creates a new Flutter-based application.
|
||||||
|
*
|
||||||
|
* Returns: a new #MyApplication.
|
||||||
|
*/
|
||||||
|
MyApplication* my_application_new();
|
||||||
|
|
||||||
|
#endif // FLUTTER_MY_APPLICATION_H_
|
818
pubspec.lock
Normal file
818
pubspec.lock
Normal file
@ -0,0 +1,818 @@
|
|||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "61.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.13.0"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.12.0"
|
||||||
|
bloc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: bloc
|
||||||
|
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.0"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
build_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_config
|
||||||
|
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
build_daemon:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_daemon
|
||||||
|
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.4"
|
||||||
|
build_resolvers:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_resolvers
|
||||||
|
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.2"
|
||||||
|
build_runner:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_runner
|
||||||
|
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.13"
|
||||||
|
build_runner_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_runner_core
|
||||||
|
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.3.2"
|
||||||
|
built_collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_collection
|
||||||
|
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
built_value:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_value
|
||||||
|
sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.9.5"
|
||||||
|
characters:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: characters
|
||||||
|
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
code_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: code_builder
|
||||||
|
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.10.1"
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.19.1"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+2"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
dartx:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dartx
|
||||||
|
sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
equatable:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: equatable
|
||||||
|
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.7"
|
||||||
|
fake_async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fake_async
|
||||||
|
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "8986dec4581b4bcd4b6df5d75a2ea0bede3db802f500635d05fa8be298f9467f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.1.2"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
fl_chart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fl_chart
|
||||||
|
sha256: f2e9137f261d0f53a820f6b829c80ba570ac915284c8e32789d973834796eca0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.71.0"
|
||||||
|
flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_bloc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_bloc
|
||||||
|
sha256: "1046d719fbdf230330d3443187cc33cc11963d15c9089f6cc56faa42a4c5f0cc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.1.0"
|
||||||
|
flutter_lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_lints
|
||||||
|
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
|
flutter_picker_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_picker_plus
|
||||||
|
sha256: "357f81676edb657b589221ad079dc7d1c68e175046d0afd609d2cab3531e7dd7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.28"
|
||||||
|
flutter_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
freezed:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: freezed
|
||||||
|
sha256: "24f77b50776d4285cc4b3a1665bb79852714c09b878363efbe64788c179c4284"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.4"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
get_it:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: get_it
|
||||||
|
sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.3"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
grouped_list:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: grouped_list
|
||||||
|
sha256: c52551bc17699e304634d4653b824a1aa7c6b1d3a2c1a0da1a80839f867353fb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.2"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.2"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
|
isar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: isar
|
||||||
|
sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0+1"
|
||||||
|
isar_flutter_libs:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: isar_flutter_libs
|
||||||
|
sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0+1"
|
||||||
|
isar_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: isar_generator
|
||||||
|
sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0+1"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.7"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.9.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.8"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.9"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
lints:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.17"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.1"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.16.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
path:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.1"
|
||||||
|
path_provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.17"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.6"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.8"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
pubspec_parse:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pubspec_parse
|
||||||
|
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.0"
|
||||||
|
searchfield:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: searchfield
|
||||||
|
sha256: "223fca0828ec95f45501db93feac7b120b93600760c0d8c04039fb2eeed9cc20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.7"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.2"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
sky_engine:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.0"
|
||||||
|
source_span:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.1"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.12.1"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.2"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.4"
|
||||||
|
time:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: time
|
||||||
|
sha256: "370572cf5d1e58adcb3e354c47515da3f7469dac3a95b447117e728e7be6f461"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
timing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timing
|
||||||
|
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
vector_math:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_math
|
||||||
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "14.3.1"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: bfe6f435f6ec49cb6c01da1e275ae4228719e59a6b067048c51e72d9d63bcc4b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.12.0"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
xxh3:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xxh3
|
||||||
|
sha256: "399a0438f5d426785723c99da6b16e136f4953fb1e9db0bf270bd41dd4619916"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.7.0 <4.0.0"
|
||||||
|
flutter: ">=3.27.0"
|
36
pubspec.yaml
Normal file
36
pubspec.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: okane
|
||||||
|
description: "A cross-platform finance tracker."
|
||||||
|
publish_to: 'none'
|
||||||
|
|
||||||
|
version: 1.0.0+1
|
||||||
|
environment:
|
||||||
|
sdk: ^3.7.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_bloc: 9.1.0
|
||||||
|
bloc:
|
||||||
|
cupertino_icons: ^1.0.8
|
||||||
|
freezed_annotation: 2.4.4
|
||||||
|
path_provider: ^2.1.5
|
||||||
|
get_it: ^8.0.3
|
||||||
|
grouped_list: ^6.0.0
|
||||||
|
searchfield: ^1.2.7
|
||||||
|
file_picker: ^10.1.2
|
||||||
|
path: ^1.9.1
|
||||||
|
fl_chart: ^0.71.0
|
||||||
|
flutter_picker_plus: ^1.5.1
|
||||||
|
isar: ^3.1.0+1
|
||||||
|
isar_flutter_libs: ^3.1.0+1
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_lints: ^5.0.0
|
||||||
|
build_runner: ^2.4.13
|
||||||
|
freezed: 2.5.0
|
||||||
|
isar_generator: ^3.1.0+1
|
||||||
|
|
||||||
|
flutter:
|
||||||
|
uses-material-design: true
|
Loading…
Reference in New Issue
Block a user