6 Commits

Author SHA1 Message Date
n8r 1f39653594 Added package rename file 2024-06-02 21:53:53 -06:00
n8r e9aad1cdf5 Added 512x512 icon for flatpak 2024-06-02 18:56:37 -06:00
n8r 2c0ae00103 Added flatpak packaging stuffs 2024-06-02 17:58:51 -06:00
n8r 000f409052 Removed helpers lib and updated to flutter 3.22 2024-05-30 20:44:06 -06:00
n8r 64baa04a47 Added gen files 2024-05-30 19:11:46 -06:00
n8r ddba989576 Added nix files and updated helpers library for dart 3 2024-05-04 23:02:28 -06:00
49 changed files with 2070 additions and 585 deletions
+2
View File
@@ -0,0 +1,2 @@
use flake
layout node
+3 -1
View File
@@ -44,4 +44,6 @@ app.*.map.json
/android/app/release /android/app/release
#generated files #generated files
lib/**/*.g.dart # lib/**/*.g.dart
.direnv/
*.tar.gz
+1 -1
View File
@@ -5,4 +5,4 @@ linux
.metadata .metadata
analysis_options.yaml analysis_options.yaml
pubspec.lock pubspec.lock
// lib/**/*.g.dart lib/**/*.g.dart
+18
View File
@@ -0,0 +1,18 @@
{androidenv}:
androidenv.composeAndroidPackages {
toolsVersion = "26.1.1";
platformToolsVersion = "34.0.5";
buildToolsVersions = [ "30.0.3" ];
includeEmulator = false;
emulatorVersion = "34.1.9";
platformVersions = [ "28" "29" "30" "31" "32" "33" "34" ];
includeSources = false;
includeSystemImages = false;
systemImageTypes = [ "google_apis_playstore" ];
abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
cmakeVersions = [ "3.10.2" ];
includeNDK = true;
ndkVersions = [ "22.0.7026061" ];
useGoogleAPIs = false;
useGoogleTVAddOns = false;
}
+5
View File
@@ -0,0 +1,5 @@
source "https://rubygems.org"
gem "fastlane"
# Gem for fetching flutter version
gem 'fastlane-plugin-flutter_version', '~> 1.0', '>= 1.0.1'
+220
View File
@@ -0,0 +1,220 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.7)
base64
nkf
rexml
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.912.0)
aws-sdk-core (3.191.6)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.78.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.146.1)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.110.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.3.1)
fastlane (2.220.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored (~> 1.2)
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
fastlane-plugin-flutter_version (1.1.15)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.7.0)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.4.0)
google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.2)
json (2.7.2)
jwt (2.8.1)
base64
mini_magick (4.12.0)
mini_mime (1.1.5)
multi_json (1.15.0)
multipart-post (2.4.0)
nanaimo (0.3.0)
naturally (2.2.1)
nkf (0.2.0)
optparse (0.4.0)
os (1.1.4)
plist (3.7.1)
public_suffix (5.0.5)
rake (13.2.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.6)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.5)
signet (0.19.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unicode-display_width (2.5.0)
word_wrap (1.0.0)
xcodeproj (1.24.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
x86_64-linux
DEPENDENCIES
fastlane
fastlane-plugin-flutter_version (~> 1.0, >= 1.0.1)
BUNDLED WITH
2.3.26
+1 -1
View File
@@ -44,7 +44,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.rluv" applicationId "com.fosscat.rluv"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion minSdkVersion flutter.minSdkVersion
+1 -1
View File
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rluv"> package="com.fosscat.rluv">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
+1 -1
View File
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rluv"> package="com.fosscat.rluv">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application <application
@@ -1,4 +1,4 @@
package com.example.rluv package com.fosscat.rluv
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
+1 -1
View File
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rluv"> package="com.fosscat.rluv">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
+914
View File
@@ -0,0 +1,914 @@
{
addressable = {
dependencies = ["public_suffix"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0irbdwkkjwzajq1ip6ba46q49sxnrl2cw7ddkdhsfhb6aprnm3vr";
type = "gem";
};
version = "2.8.6";
};
artifactory = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0qzj389l2a3zig040h882mf6cxfa71pm2nk51l4p85n3ck4xa8rh";
type = "gem";
};
version = "3.0.17";
};
atomos = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "17vq6sjyswr5jfzwdccw748kgph6bdw30bakwnn6p8sl4hpv4hvx";
type = "gem";
};
version = "0.1.3";
};
aws-eventstream = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0gvdg4yx4p9av2glmp7vsxhs0n8fj1ga9kq2xdb8f95j7b04qhzi";
type = "gem";
};
version = "1.3.0";
};
aws-partitions = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0vpwich545z3lyslis1mikgs9scm6fs9g2yjsqq6jv3a7nx355nd";
type = "gem";
};
version = "1.912.0";
};
aws-sdk-core = {
dependencies = ["aws-eventstream" "aws-partitions" "aws-sigv4" "jmespath"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "08h9apxdn2aflkg751j4i56ks4750znfbj56w4zlxf4jk7jxkbyk";
type = "gem";
};
version = "3.191.6";
};
aws-sdk-kms = {
dependencies = ["aws-sdk-core" "aws-sigv4"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0fbp2vw5qnyiya63hlmwiqkbh30lipyqplancmhm84ad7i98ambb";
type = "gem";
};
version = "1.78.0";
};
aws-sdk-s3 = {
dependencies = ["aws-sdk-core" "aws-sdk-kms" "aws-sigv4"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1al80phz4x9wwfnr07q1l8h5f0qxgfrrycbg8jvznhxm3zhrakrq";
type = "gem";
};
version = "1.146.1";
};
aws-sigv4 = {
dependencies = ["aws-eventstream"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1g3w27wzjy4si6kp49w10as6ml6g6zl3xrfqs5ikpfciidv9kpc4";
type = "gem";
};
version = "1.8.0";
};
babosa = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "16dwqn33kmxkqkv51cwiikdkbrdjfsymlnc0rgbjwilmym8a9phq";
type = "gem";
};
version = "1.0.4";
};
base64 = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "01qml0yilb9basf7is2614skjp8384h2pycfx86cr8023arfj98g";
type = "gem";
};
version = "0.2.0";
};
CFPropertyList = {
dependencies = ["base64" "nkf" "rexml"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0k1w5i4lb1z941m7ds858nly33f3iv12wvr1zav5x3fa99hj2my4";
type = "gem";
};
version = "3.0.7";
};
claide = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0bpqhc0kqjp1bh9b7ffc395l9gfls0337rrhmab4v46ykl45qg3d";
type = "gem";
};
version = "1.1.0";
};
colored = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0b0x5jmsyi0z69bm6sij1k89z7h0laag3cb4mdn7zkl9qmxb90lx";
type = "gem";
};
version = "1.2";
};
colored2 = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0jlbqa9q4mvrm73aw9mxh23ygzbjiqwisl32d8szfb5fxvbjng5i";
type = "gem";
};
version = "3.1.2";
};
commander = {
dependencies = ["highline"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1n8k547hqq9hvbyqbx2qi08g0bky20bbjca1df8cqq5frhzxq7bx";
type = "gem";
};
version = "4.6.0";
};
declarative = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1yczgnqrbls7shrg63y88g7wand2yp9h6sf56c9bdcksn5nds8c0";
type = "gem";
};
version = "0.0.20";
};
digest-crc = {
dependencies = ["rake"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "09114ndpnnyamc2q07bmpzw7kp3rbbfv7plmxcbzzi9d6prmd92w";
type = "gem";
};
version = "0.6.5";
};
domain_name = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0cyr2xm576gqhqicsyqnhanni47408w2pgvrfi8pd13h2li3nsaz";
type = "gem";
};
version = "0.6.20240107";
};
dotenv = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1n0pi8x8ql5h1mijvm8lgn6bhq4xjb5a500p5r1krq4s6j9lg565";
type = "gem";
};
version = "2.8.1";
};
emoji_regex = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0jsnrkfy345v66jlm2xrz8znivfnamg3mfzkddn414bndf2vxn7c";
type = "gem";
};
version = "3.2.3";
};
excon = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1m3gzvp1wqki0yh4b7761qhdy4pyr4phy429b7s9w25nrkhp4lsz";
type = "gem";
};
version = "0.110.0";
};
faraday = {
dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-multipart" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "faraday-retry" "ruby2_keywords"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1c760q0ks4vj4wmaa7nh1dgvgqiwaw0mjr7v8cymy7i3ffgjxx90";
type = "gem";
};
version = "1.10.3";
};
faraday-cookie_jar = {
dependencies = ["faraday" "http-cookie"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "00hligx26w9wdnpgsrf0qdnqld4rdccy8ym6027h5m735mpvxjzk";
type = "gem";
};
version = "0.0.7";
};
faraday-em_http = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "12cnqpbak4vhikrh2cdn94assh3yxza8rq2p9w2j34bqg5q4qgbs";
type = "gem";
};
version = "1.0.0";
};
faraday-em_synchrony = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vgrbhkp83sngv6k4mii9f2s9v5lmp693hylfxp2ssfc60fas3a6";
type = "gem";
};
version = "1.0.0";
};
faraday-excon = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0h09wkb0k0bhm6dqsd47ac601qiaah8qdzjh8gvxfd376x1chmdh";
type = "gem";
};
version = "1.1.0";
};
faraday-httpclient = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0fyk0jd3ks7fdn8nv3spnwjpzx2lmxmg2gh4inz3by1zjzqg33sc";
type = "gem";
};
version = "1.0.1";
};
faraday-multipart = {
dependencies = ["multipart-post"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "09871c4hd7s5ws1wl4gs7js1k2wlby6v947m2bbzg43pnld044lh";
type = "gem";
};
version = "1.0.4";
};
faraday-net_http = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1fi8sda5hc54v1w3mqfl5yz09nhx35kglyx72w7b8xxvdr0cwi9j";
type = "gem";
};
version = "1.0.1";
};
faraday-net_http_persistent = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0dc36ih95qw3rlccffcb0vgxjhmipsvxhn6cw71l7ffs0f7vq30b";
type = "gem";
};
version = "1.2.0";
};
faraday-patron = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "19wgsgfq0xkski1g7m96snv39la3zxz6x7nbdgiwhg5v82rxfb6w";
type = "gem";
};
version = "1.0.0";
};
faraday-rack = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1h184g4vqql5jv9s9im6igy00jp6mrah2h14py6mpf9bkabfqq7g";
type = "gem";
};
version = "1.0.0";
};
faraday-retry = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "153i967yrwnswqgvnnajgwp981k9p50ys1h80yz3q94rygs59ldd";
type = "gem";
};
version = "1.0.3";
};
faraday_middleware = {
dependencies = ["faraday"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1bw8mfh4yin2xk7138rg3fhb2p5g2dlmdma88k82psah9mbmvlfy";
type = "gem";
};
version = "1.2.0";
};
fastimage = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1sfc7svf7h1ja6zmsq9f3ps6pg0q4hymphh6rk7ipmp7ygqjkii3";
type = "gem";
};
version = "2.3.1";
};
fastlane = {
dependencies = ["CFPropertyList" "addressable" "artifactory" "aws-sdk-s3" "babosa" "colored" "commander" "dotenv" "emoji_regex" "excon" "faraday" "faraday-cookie_jar" "faraday_middleware" "fastimage" "gh_inspector" "google-apis-androidpublisher_v3" "google-apis-playcustomapp_v1" "google-cloud-env" "google-cloud-storage" "highline" "http-cookie" "json" "jwt" "mini_magick" "multipart-post" "naturally" "optparse" "plist" "rubyzip" "security" "simctl" "terminal-notifier" "terminal-table" "tty-screen" "tty-spinner" "word_wrap" "xcodeproj" "xcpretty" "xcpretty-travis-formatter"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "14ywmlipmryzdxzn4235ah67hy06wh5hf32jbs3a9j7byc2x1kx3";
type = "gem";
};
version = "2.220.0";
};
fastlane-plugin-flutter_version = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "10lyrljpaic2gj9znpw6lh6y46l96jf85q9k62nl9sdklg888m8x";
type = "gem";
};
version = "1.1.15";
};
gh_inspector = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0f8r9byajj3bi2c7c5sqrc7m0zrv3nblfcd4782lw5l73cbsgk04";
type = "gem";
};
version = "1.1.3";
};
google-apis-androidpublisher_v3 = {
dependencies = ["google-apis-core"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "046j100lrh5dhb8p3gr38fyqrw8vcif97pqb55ysipy874lafw49";
type = "gem";
};
version = "0.54.0";
};
google-apis-core = {
dependencies = ["addressable" "googleauth" "httpclient" "mini_mime" "representable" "retriable" "rexml"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "15ycm7al9dizabbqmri5xmiz8mbcci343ygb64ndbmr9n49p08a3";
type = "gem";
};
version = "0.11.3";
};
google-apis-iamcredentials_v1 = {
dependencies = ["google-apis-core"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ysil0bkh755kmf9xvw5szhk1yyh3gqzwfsrbwsrl77gsv7jarcs";
type = "gem";
};
version = "0.17.0";
};
google-apis-playcustomapp_v1 = {
dependencies = ["google-apis-core"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1mlgwiid5lgg41y7qk8ca9lzhwx5njs25hz5fbf1mdal0kwm37lm";
type = "gem";
};
version = "0.13.0";
};
google-apis-storage_v1 = {
dependencies = ["google-apis-core"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "13yvc9r8bhs16vq3fjc93qlffmq9p6zx97c9g1c3wh0jbrvwrs03";
type = "gem";
};
version = "0.31.0";
};
google-cloud-core = {
dependencies = ["google-cloud-env" "google-cloud-errors"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0dagdfx3rnk9xplnj19gqpqn41fd09xfn8lp2p75psihhnj2i03l";
type = "gem";
};
version = "1.7.0";
};
google-cloud-env = {
dependencies = ["faraday"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "05gshdqscg4kil6ppfzmikyavsx449bxyj47j33r4n4p8swsqyb1";
type = "gem";
};
version = "1.6.0";
};
google-cloud-errors = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "056yw9cg771c1xqvw15wpdfdw9lz3m13fh5b6a3p1c9xaq7jwkhb";
type = "gem";
};
version = "1.4.0";
};
google-cloud-storage = {
dependencies = ["addressable" "digest-crc" "google-apis-iamcredentials_v1" "google-apis-storage_v1" "google-cloud-core" "googleauth" "mini_mime"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0xpb3s7zr7g647xg66y2mavdargk5ixsfbfdmi4m2jc3khdd0hxm";
type = "gem";
};
version = "1.47.0";
};
googleauth = {
dependencies = ["faraday" "jwt" "multi_json" "os" "signet"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ry9v23kndgx2pxq9v31l68k9lnnrcz1w4v75bkxq88jmbddljl1";
type = "gem";
};
version = "1.8.1";
};
highline = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0yclf57n2j3cw8144ania99h1zinf8q3f5zrhqa754j6gl95rp9d";
type = "gem";
};
version = "2.0.3";
};
http-cookie = {
dependencies = ["domain_name"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "13rilvlv8kwbzqfb644qp6hrbsj82cbqmnzcvqip1p6vqx36sxbk";
type = "gem";
};
version = "1.0.5";
};
httpclient = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "19mxmvghp7ki3klsxwrlwr431li7hm1lczhhj8z4qihl2acy8l99";
type = "gem";
};
version = "2.8.3";
};
jmespath = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1cdw9vw2qly7q7r41s7phnac264rbsdqgj4l0h4nqgbjb157g393";
type = "gem";
};
version = "1.6.2";
};
json = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0b4qsi8gay7ncmigr0pnbxyb17y3h8kavdyhsh7nrlqwr35vb60q";
type = "gem";
};
version = "2.7.2";
};
jwt = {
dependencies = ["base64"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "02m3vza49pb9dirwpn8vmzbcypi3fc6l3a9dh253jwm1121g7ajb";
type = "gem";
};
version = "2.8.1";
};
mini_magick = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0slh78f9z6n0l1i2km7m48yz7l4fjrk88sj1f4mh1wb39sl2yc37";
type = "gem";
};
version = "4.12.0";
};
mini_mime = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vycif7pjzkr29mfk4dlqv3disc5dn0va04lkwajlpr1wkibg0c6";
type = "gem";
};
version = "1.1.5";
};
multi_json = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z";
type = "gem";
};
version = "1.15.0";
};
multipart-post = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1033p35166d9p97y4vajbbvr13pmkk9zwn7sylxpmk9jrpk8ri67";
type = "gem";
};
version = "2.4.0";
};
nanaimo = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0xi36h3f7nm8bc2k0b6svpda1lyank2gf872lxjbhw3h95hdrbma";
type = "gem";
};
version = "0.3.0";
};
naturally = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "04x1nkx6gkqzlc4phdvq05v3vjds6mgqhjqzqpcs6vdh5xyqrf59";
type = "gem";
};
version = "2.2.1";
};
nkf = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "09piyp2pd74klb9wcn0zw4mb5l0k9wzwppxggxi1yi95l2ym3hgv";
type = "gem";
};
version = "0.2.0";
};
optparse = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1pmsn1g1q5fpkjrc4h1wlw6lxlqp165sdcd951xyl47n6k0az17m";
type = "gem";
};
version = "0.4.0";
};
os = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0gwd20smyhxbm687vdikfh1gpi96h8qb1x28s2pdcysf6dm6v0ap";
type = "gem";
};
version = "1.1.4";
};
plist = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0b643i5b7b7galvlb2fc414ifmb78b5lsq47gnvhzl8m27dl559z";
type = "gem";
};
version = "3.7.1";
};
public_suffix = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "14y4vzjwf5gp0mqgs880kis0k7n2biq8i6ci6q2n315kichl1hvj";
type = "gem";
};
version = "5.0.5";
};
rake = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "17850wcwkgi30p7yqh60960ypn7yibacjjha0av78zaxwvd3ijs6";
type = "gem";
};
version = "13.2.1";
};
representable = {
dependencies = ["declarative" "trailblazer-option" "uber"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1kms3r6w6pnryysnaqqa9fsn0v73zx1ilds9d1c565n3xdzbyafc";
type = "gem";
};
version = "3.2.0";
};
retriable = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1q48hqws2dy1vws9schc0kmina40gy7sn5qsndpsfqdslh65snha";
type = "gem";
};
version = "3.1.2";
};
rexml = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "05i8518ay14kjbma550mv0jm8a6di8yp5phzrd8rj44z9qnrlrp0";
type = "gem";
};
version = "3.2.6";
};
rouge = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0sfikq1q8xyqqx690iiz7ybhzx87am4w50w8f2nq36l3asw4x89d";
type = "gem";
};
version = "2.0.7";
};
ruby2_keywords = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz";
type = "gem";
};
version = "0.0.5";
};
rubyzip = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0grps9197qyxakbpw02pda59v45lfgbgiyw48i0mq9f2bn9y6mrz";
type = "gem";
};
version = "2.3.2";
};
security = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1drkm2wgjazwzj09db1szrllkag036bdvc3dr42fh1kpr877m5rs";
type = "gem";
};
version = "0.1.5";
};
signet = {
dependencies = ["addressable" "faraday" "jwt" "multi_json"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0cfxa11wy1nv9slmnzjczkdgld0gqizajsb03rliy53zylwkjzsk";
type = "gem";
};
version = "0.19.0";
};
simctl = {
dependencies = ["CFPropertyList" "naturally"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0sr3z4kmp6ym7synicyilj9vic7i9nxgaszqx6n1xn1ss7s7g45r";
type = "gem";
};
version = "1.6.10";
};
terminal-notifier = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1slc0y8pjpw30hy21v8ypafi8r7z9jlj4bjbgz03b65b28i2n3bs";
type = "gem";
};
version = "2.0.0";
};
terminal-table = {
dependencies = ["unicode-display_width"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "14dfmfjppmng5hwj7c5ka6qdapawm3h6k9lhn8zj001ybypvclgr";
type = "gem";
};
version = "3.0.2";
};
trailblazer-option = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "18s48fndi2kfvrfzmq6rxvjfwad347548yby0341ixz1lhpg3r10";
type = "gem";
};
version = "0.1.2";
};
tty-cursor = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0j5zw041jgkmn605ya1zc151bxgxl6v192v2i26qhxx7ws2l2lvr";
type = "gem";
};
version = "0.7.1";
};
tty-screen = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0l4vh6g333jxm9lakilkva2gn17j6gb052626r1pdbmy2lhnb460";
type = "gem";
};
version = "0.8.2";
};
tty-spinner = {
dependencies = ["tty-cursor"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0hh5awmijnzw9flmh5ak610x1d00xiqagxa5mbr63ysggc26y0qf";
type = "gem";
};
version = "0.9.3";
};
uber = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1p1mm7mngg40x05z52md3mbamkng0zpajbzqjjwmsyw0zw3v9vjv";
type = "gem";
};
version = "0.1.0";
};
unicode-display_width = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1d0azx233nags5jx3fqyr23qa2rhgzbhv8pxp46dgbg1mpf82xky";
type = "gem";
};
version = "2.5.0";
};
word_wrap = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1iyc5bc7dbgsd8j3yk1i99ral39f23l6wapi0083fbl19hid8mpm";
type = "gem";
};
version = "1.0.0";
};
xcodeproj = {
dependencies = ["CFPropertyList" "atomos" "claide" "colored2" "nanaimo" "rexml"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1wpg4n7b8571j2h8h7v2kk8pr141rgf6m8mhk221k990fissrq56";
type = "gem";
};
version = "1.24.0";
};
xcpretty = {
dependencies = ["rouge"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1xq47q2h5llj7b54rws4796904vnnjz7qqnacdv7wlp3gdbwrivm";
type = "gem";
};
version = "0.3.0";
};
xcpretty-travis-formatter = {
dependencies = ["xcpretty"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "14rg4f70klrs910n7rsgfa4dn8s2qyny55194ax2qyyb2wpk7k5a";
type = "gem";
};
version = "1.0.1";
};
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Build the Flutter app and package into an archive.
# Exit if any command fails
set -e
# Echo all commands for debug purposes
set -x
projectName=rluvApp
archiveName=$projectName-Linux-Portable.tar.gz
baseDir=$(pwd)
# ----------------------------- Build Flutter app ---------------------------- #
flutter pub get
flutter build linux
cd build/linux/arm64/release/bundle || exit
tar -czaf $archiveName ./*
mv $archiveName "$baseDir"/
Generated
+186
View File
@@ -0,0 +1,186 @@
{
"nodes": {
"android-nixpkgs": {
"inputs": {
"devshell": "devshell",
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1712088936,
"narHash": "sha256-mVjeSWQiR/t4UZ9fUawY9OEPAhY1R3meYG+0oh8DUBs=",
"owner": "tadfisher",
"repo": "android-nixpkgs",
"rev": "2d8181caef279f19c4a33dc694723f89ffc195d4",
"type": "github"
},
"original": {
"owner": "tadfisher",
"repo": "android-nixpkgs",
"type": "github"
}
},
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"android-nixpkgs",
"nixpkgs"
]
},
"locked": {
"lastModified": 1711099426,
"narHash": "sha256-HzpgM/wc3aqpnHJJ2oDqPBkNsqWbW0WfWUO8lKu8nGk=",
"owner": "numtide",
"repo": "devshell",
"rev": "2d45b54ca4a183f2fdcf4b19c895b64fbf620ee8",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1711703276,
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1716948383,
"narHash": "sha256-SzDKxseEcHR5KzPXLwsemyTR/kaM9whxeiJohbL04rs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ad57eef4ef0659193044870c731987a6df5cf56b",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"android-nixpkgs": "android-nixpkgs",
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_2"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+54
View File
@@ -0,0 +1,54 @@
{
description = "An example project using flutter";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.android-nixpkgs.url = "github:tadfisher/android-nixpkgs";
outputs = {
self,
flake-utils,
nixpkgs,
...
} @ inputs:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
};
in {
devShell = let
android-nixpkgs = pkgs.callPackage inputs.android-nixpkgs {};
android-sdk = android-nixpkgs.sdk (sdkPkgs:
with sdkPkgs; [
cmdline-tools-latest
build-tools-30-0-3
# This version needs to match the GRADLE_OPTS env var down below, vice versa
build-tools-34-0-0
platform-tools
platforms-android-28
platforms-android-29
platforms-android-31
platforms-android-33
platforms-android-34
emulator
]);
in
pkgs.mkShell {
# Fix an issue with Flutter using an older version of aapt2, which does not know
# an used parameter.
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${android-sdk}/share/android-sdk/build-tools/34.0.0/aapt2";
FLUTTER_ROOT = "${pkgs.flutter}";
# nativeBuildInputs = with pkgs; [
# ];
buildInputs = with pkgs; [
flutter
# pkg-config
jdk17
android-sdk
];
shellHook = ''
export PATH="$PATH":"$HOME/.pub-cache/bin"
'';
};
});
}
+3 -3
View File
@@ -296,7 +296,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv; PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -424,7 +424,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv; PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -446,7 +446,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv; PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
+2 -2
View File
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Rluv</string> <string>rluv</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>rluv</string> <string>fosscatrluv</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:rluv/features/account/signup.dart'; import 'package:rluv/features/account/signup.dart';
import 'package:rluv/global/styles.dart'; import 'package:rluv/global/styles.dart';
@@ -13,8 +12,7 @@ class AccountCreateScreen extends ConsumerStatefulWidget {
const AccountCreateScreen({super.key}); const AccountCreateScreen({super.key});
@override @override
ConsumerState<AccountCreateScreen> createState() => ConsumerState<AccountCreateScreen> createState() => _AccountCreateScreenState();
_AccountCreateScreenState();
} }
enum _AccountScreen { options, login, signup } enum _AccountScreen { options, login, signup }
@@ -40,7 +38,7 @@ class _AccountCreateScreenState extends ConsumerState<AccountCreateScreen> {
}, },
); );
} }
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
return Scaffold( return Scaffold(
backgroundColor: Styles.purpleNurple, backgroundColor: Styles.purpleNurple,
body: SafeArea( body: SafeArea(
@@ -60,11 +58,8 @@ class _AccountCreateScreenState extends ConsumerState<AccountCreateScreen> {
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 40.0), padding: const EdgeInsets.symmetric(vertical: 40.0),
child: Image.asset("assets/app_icon.png", child: Image.asset("assets/app_icon.png",
height: height: screen.width > 500 ? 250 : screen.width * 0.5,
screen.width > 500 ? 250 : screen.width * 0.5, width: screen.width > 500 ? 250 : screen.width * 0.5),
width: screen.width > 500
? 250
: screen.width * 0.5),
), ),
UiButton( UiButton(
color: Styles.sunflower, color: Styles.sunflower,
+12 -27
View File
@@ -1,7 +1,6 @@
import 'package:colorful_print/colorful_print.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:helpers/helpers/print.dart';
import '../../global/api.dart'; import '../../global/api.dart';
import '../../global/styles.dart'; import '../../global/styles.dart';
@@ -19,7 +18,7 @@ class Login extends ConsumerStatefulWidget {
} }
class _LoginState extends ConsumerState<Login> { class _LoginState extends ConsumerState<Login> {
bool usingUsername = false; bool usingUsername = true;
final emailController = TextEditingController(); final emailController = TextEditingController();
final usernameController = TextEditingController(); final usernameController = TextEditingController();
final passwordController = TextEditingController(); final passwordController = TextEditingController();
@@ -32,7 +31,7 @@ class _LoginState extends ConsumerState<Login> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
return Form( return Form(
key: widget.formKey, key: widget.formKey,
child: Stack( child: Stack(
@@ -134,7 +133,7 @@ class _LoginState extends ConsumerState<Login> {
text: 'Password: ', text: 'Password: ',
validatorFunc: (s) { validatorFunc: (s) {
if (s != null && s.length < 6) { if (s != null && s.length < 6) {
return 'Please do a better password (you have to)'; return 'Please do a better password, at least 6 characters (you have to)';
} }
return null; return null;
}, },
@@ -205,35 +204,21 @@ class _LoginState extends ConsumerState<Login> {
Future login() async { Future login() async {
try { try {
if (widget.formKey.currentState != null && if (widget.formKey.currentState != null && !widget.formKey.currentState!.validate()) {
!widget.formKey.currentState!.validate()) {
return; return;
} }
final data = final Map<String, dynamic>? data = await ref.read(apiProvider.notifier).post(path: 'auth/login', data: {
await ref.read(apiProvider.notifier).post(path: 'auth/login', data: { 'username': usernameController.text.isEmpty ? null : usernameController.text,
'username':
usernameController.text.isEmpty ? null : usernameController.text,
'email': emailController.text.isEmpty ? null : emailController.text, 'email': emailController.text.isEmpty ? null : emailController.text,
'password': passwordController.text, 'password': passwordController.text,
}); });
String message = 'Login unsuccessful'; bool success = data?['success'] ?? false;
bool success = data?['success'] == 'false'; String message = data?['message'] ?? (success ? 'Login success!' : 'Login unsuccessful.');
if (data != null) { printColor(data, textColor: TextColor.yellow);
if (data['message'] != null) { showSnack(ref: ref, text: message, type: success ? SnackType.success : SnackType.error);
message = data['message'];
} else if (success) {
message = 'Logged in!';
}
}
// final bool success = data?['success'] ?? false;
printAmber(data);
showSnack(
ref: ref,
text: message,
type: !success ? SnackType.error : SnackType.success);
} catch (err, st) { } catch (err, st) {
printRed('Error in login: $err\n$st'); printColor('Error in login: $err\n$st', textColor: TextColor.red);
} }
} }
} }
+12 -24
View File
@@ -1,7 +1,6 @@
import 'package:colorful_print/colorful_print.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:helpers/helpers/print.dart';
import '../../global/api.dart'; import '../../global/api.dart';
import '../../global/styles.dart'; import '../../global/styles.dart';
@@ -36,7 +35,7 @@ class _SignupState extends ConsumerState<Signup> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
return Form( return Form(
key: widget.formKey, key: widget.formKey,
child: Stack( child: Stack(
@@ -126,8 +125,7 @@ class _SignupState extends ConsumerState<Signup> {
), ),
UiButton( UiButton(
width: screen.width * 0.4, width: screen.width * 0.4,
icon: const Icon(Icons.cancel, icon: const Icon(Icons.cancel, color: Styles.washedStone, size: 20),
color: Styles.washedStone, size: 20),
onPressed: () { onPressed: () {
setState( setState(
() => hasFamilyCode = false, () => hasFamilyCode = false,
@@ -140,9 +138,7 @@ class _SignupState extends ConsumerState<Signup> {
: Padding( : Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: UiButton( child: UiButton(
width: screen.width * 0.5 > 400 width: screen.width * 0.5 > 400 ? 400 : screen.width * 0.5,
? 400
: screen.width * 0.5,
text: 'JOIN FAMILY', text: 'JOIN FAMILY',
// color: Styles.flounderBlue, // color: Styles.flounderBlue,
onPressed: () { onPressed: () {
@@ -190,8 +186,7 @@ class _SignupState extends ConsumerState<Signup> {
text, text,
style: TextStyle(fontSize: size.width < 350 ? 16 : 20), style: TextStyle(fontSize: size.width < 350 ? 16 : 20),
), ),
if (subtext != null) if (subtext != null) Text(subtext, style: const TextStyle(fontSize: 12)),
Text(subtext, style: const TextStyle(fontSize: 12)),
], ],
), ),
), ),
@@ -223,36 +218,29 @@ class _SignupState extends ConsumerState<Signup> {
Future signup() async { Future signup() async {
try { try {
if (widget.formKey.currentState != null && if (widget.formKey.currentState != null && !widget.formKey.currentState!.validate()) {
!widget.formKey.currentState!.validate()) {
return; return;
} }
final data = final data = await ref.read(apiProvider.notifier).post(path: 'auth/signup', data: {
await ref.read(apiProvider.notifier).post(path: 'auth/signup', data: {
'name': nameCotroller.text, 'name': nameCotroller.text,
'username': 'username': usernameController.text.isEmpty ? null : usernameController.text,
usernameController.text.isEmpty ? null : usernameController.text,
'email': emailController.text.isEmpty ? null : emailController.text, 'email': emailController.text.isEmpty ? null : emailController.text,
'password': passwordController.text, 'password': passwordController.text,
'family_code': familyCodeController.text.isEmpty 'family_code': familyCodeController.text.isEmpty ? null : familyCodeController.text.toUpperCase(),
? null
: familyCodeController.text.toUpperCase(),
'budget_name': 'Budget' 'budget_name': 'Budget'
}); });
final success = data?['success'] ?? false; final success = data?['success'] ?? false;
showSnack( showSnack(
ref: ref, ref: ref,
text: data?['message'] ?? success text: data?['message'] ?? success ? 'Login successful' : 'Login unsuccessful',
? 'Login successful'
: 'Login unsuccessful',
type: !success ? SnackType.error : SnackType.success); type: !success ? SnackType.error : SnackType.success);
printAmber(data); printColor(data, textColor: TextColor.yellow);
// final user = User.fromJson(data?['user']); // final user = User.fromJson(data?['user']);
// ref.read(tokenProvider.notifier).state = // ref.read(tokenProvider.notifier).state =
} catch (err) { } catch (err) {
printRed(err); printColor(err, textColor: TextColor.red);
} }
} }
} }
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers.dart';
import 'package:rluv/features/budget/screens/transactions_listview.dart'; import 'package:rluv/features/budget/screens/transactions_listview.dart';
import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart'; import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
import 'package:rluv/features/budget/widgets/budget_category_bar.dart'; import 'package:rluv/features/budget/widgets/budget_category_bar.dart';
@@ -19,8 +18,7 @@ class BudgetOverviewScreen extends ConsumerStatefulWidget {
final Map<String, dynamic> initialData; final Map<String, dynamic> initialData;
@override @override
ConsumerState<BudgetOverviewScreen> createState() => ConsumerState<BudgetOverviewScreen> createState() => _BudgetOverviewScreenState();
_BudgetOverviewScreenState();
} }
class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> { class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
@@ -30,23 +28,18 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
final budget = ref.watch(budgetProvider); final budget = ref.watch(budgetProvider);
final budgetCategories = ref.watch(budgetCategoriesProvider); final budgetCategories = ref.watch(budgetCategoriesProvider);
final transactions = ref.watch(transactionsProvider); final transactions = ref.watch(transactionsProvider);
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
double netExpense = 0.0; double netExpense = 0.0;
double netIncome = 0.0; double netIncome = 0.0;
double expectedExpenses = 0.0; double expectedExpenses = 0.0;
Map<int, double> budgetCategoryNetMap = {}; Map<int, double> budgetCategoryNetMap = {};
netExpense = transactions netExpense =
.where((t) => t.type == TransactionType.expense) transactions.where((t) => t.type == TransactionType.expense).fold(netExpense, (net, t) => net + t.amount);
.fold(netExpense, (net, t) => net + t.amount); netIncome = transactions.where((t) => t.type == TransactionType.income).fold(netIncome, (net, t) => net + t.amount);
netIncome = transactions
.where((t) => t.type == TransactionType.income)
.fold(netIncome, (net, t) => net + t.amount);
for (final bud in budgetCategories) { for (final bud in budgetCategories) {
double net = 0.0; double net = 0.0;
expectedExpenses += bud.amount; expectedExpenses += bud.amount;
net = transactions net = transactions.where((t) => t.budgetCategoryId == bud.id).fold(net, (net, t) => net + t.amount);
.where((t) => t.budgetCategoryId == bud.id)
.fold(net, (net, t) => net + t.amount);
budgetCategoryNetMap[bud.id!] = net; budgetCategoryNetMap[bud.id!] = net;
} }
return Stack( return Stack(
@@ -64,23 +57,14 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
const Spacer(flex: 2), const Spacer(flex: 2),
Text( Text(
formatDate(DateTime.now()), formatDate(DateTime.now()),
style: const TextStyle( style: const TextStyle(fontSize: 16, color: Styles.electricBlue),
fontSize: 16, color: Styles.electricBlue),
), ),
const Spacer(), const Spacer(),
const Text('MONTHLY', const Text('MONTHLY', style: TextStyle(fontSize: 42, color: Styles.electricBlue)),
style:
TextStyle(fontSize: 42, color: Styles.electricBlue)),
const Spacer(flex: 2), const Spacer(flex: 2),
BudgetNetBar( BudgetNetBar(isPositive: true, net: netIncome, expected: budget?.expectedIncome ?? 0.0),
isPositive: true,
net: netIncome,
expected: budget?.expectedIncome ?? 0.0),
const Spacer(), const Spacer(),
BudgetNetBar( BudgetNetBar(isPositive: false, net: netExpense, expected: expectedExpenses),
isPositive: false,
net: netExpense,
expected: expectedExpenses),
const Spacer(), const Spacer(),
], ],
), ),
@@ -107,8 +91,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text( child: Text(
'BUDGET', 'BUDGET',
style: TextStyle( style: TextStyle(fontSize: 28, color: Styles.electricBlue),
fontSize: 28, color: Styles.electricBlue),
), ),
), ),
budgetCategories.isEmpty budgetCategories.isEmpty
@@ -120,24 +103,17 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
children: [ children: [
const Padding( const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text( child: Text('No budget categories created yet, add some!'),
'No budget categories created yet, add some!'),
), ),
UiButton( UiButton(
onPressed: onPressed: ref.watch(budgetProvider) == null
ref.watch(budgetProvider) ==
null
? null ? null
: () => showDialog( : () => showDialog(
context: context, context: context,
builder: (context) => Dialog( builder: (context) => Dialog(
shape: Styles shape: Styles.dialogShape,
.dialogShape, backgroundColor: Styles.dialogColor,
backgroundColor: child: const BudgetCategoryDialog()),
Styles
.dialogColor,
child:
const BudgetCategoryDialog()),
), ),
text: 'Add Category', text: 'Add Category',
), ),
@@ -146,55 +122,42 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
), ),
) )
: Padding( : Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 4.0),
horizontal: 2.0, vertical: 4.0),
child: SizedBox( child: SizedBox(
height: screen.height * 0.36, height: screen.height * 0.36,
child: Scrollbar( child: Scrollbar(
controller: budgetListScrollController, controller: budgetListScrollController,
thumbVisibility: true, thumbVisibility: true,
child: ListView( child: ListView(
physics: physics: const BouncingScrollPhysics(),
const BouncingScrollPhysics(), controller: budgetListScrollController,
controller:
budgetListScrollController,
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
...budgetCategories ...budgetCategories.map((category) {
.mapIndexed((i, category) { final int i = budgetCategories.indexOf(category);
return BudgetCategoryBar( return BudgetCategoryBar(
budgetCategory: category, budgetCategory: category,
currentAmount: currentAmount: budgetCategoryNetMap[category.id]!,
budgetCategoryNetMap[
category.id]!,
index: i, index: i,
); );
}).toList(), }).toList(),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.center,
MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width: 140, width: 140,
child: ElevatedButton( child: ElevatedButton(
onPressed: ref.watch( onPressed: ref.watch(budgetProvider) == null
budgetProvider) ==
null
? null ? null
: () => showDialog( : () => showDialog(
context: context, context: context,
builder: (context) => Dialog( builder: (context) => Dialog(
shape: Styles shape: Styles.dialogShape,
.dialogShape, backgroundColor: Styles.dialogColor,
backgroundColor: child: const BudgetCategoryDialog()),
Styles
.dialogColor,
child:
const BudgetCategoryDialog()),
), ),
child: const Text( child: const Text('Add Category'),
'Add Category'),
), ),
), ),
], ],
@@ -214,8 +177,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: padding: const EdgeInsets.only(left: 20.0, right: 15.0),
const EdgeInsets.only(left: 20.0, right: 15.0),
child: Container( child: Container(
height: 70, height: 70,
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -225,8 +187,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
child: InkWell( child: InkWell(
child: const Center( child: const Center(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 14.0),
horizontal: 20.0, vertical: 14.0),
child: FittedBox( child: FittedBox(
child: Text( child: Text(
'Transaction History', 'Transaction History',
@@ -238,10 +199,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
), ),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context, MaterialPageRoute(builder: (context) => const TransactionsListview()));
MaterialPageRoute(
builder: (context) =>
const TransactionsListview()));
}, },
), ),
), ),
@@ -292,8 +250,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
child: IconButton( child: IconButton(
icon: const Icon(Icons.loop), icon: const Icon(Icons.loop),
color: Styles.seaweedGreen, color: Styles.seaweedGreen,
onPressed: () => onPressed: () => ref.read(dashboardProvider.notifier).fetchDashboard(),
ref.read(dashboardProvider.notifier).fetchDashboard(),
), ),
), ),
), ),
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:rluv/features/budget/widgets/transaction_list_item.dart'; import 'package:rluv/features/budget/widgets/transaction_list_item.dart';
import 'package:rluv/global/styles.dart'; import 'package:rluv/global/styles.dart';
import 'package:rluv/models/transaction_model.dart'; import 'package:rluv/models/transaction_model.dart';
@@ -12,8 +11,7 @@ class TransactionsListview extends ConsumerStatefulWidget {
const TransactionsListview({super.key}); const TransactionsListview({super.key});
@override @override
ConsumerState<TransactionsListview> createState() => ConsumerState<TransactionsListview> createState() => _TransactionsListviewState();
_TransactionsListviewState();
} }
class _TransactionsListviewState extends ConsumerState<TransactionsListview> { class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
@@ -23,8 +21,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(selectedTransactionSortProvider.notifier).state = ref.read(selectedTransactionSortProvider.notifier).state = TransactionSort.all;
TransactionSort.all;
ref.read(selectedSortDateProvider.notifier).state = SortDate.decending; ref.read(selectedSortDateProvider.notifier).state = SortDate.decending;
}); });
super.initState(); super.initState();
@@ -34,8 +31,8 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final budgetCategories = ref.watch(budgetCategoriesProvider); final budgetCategories = ref.watch(budgetCategoriesProvider);
if (ref.read(selectedCategory) == null && budgetCategories.isNotEmpty) { if (ref.read(selectedCategory) == null && budgetCategories.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) => WidgetsBinding.instance
ref.read(selectedCategory.notifier).state = budgetCategories.first); .addPostFrameCallback((_) => ref.read(selectedCategory.notifier).state = budgetCategories.first);
} }
final sortType = ref.watch(selectedTransactionSortProvider); final sortType = ref.watch(selectedTransactionSortProvider);
final sortDate = ref.watch(selectedSortDateProvider); final sortDate = ref.watch(selectedSortDateProvider);
@@ -60,8 +57,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
if (ref.read(selectedCategory) != null) { if (ref.read(selectedCategory) != null) {
transactions = transactions transactions = transactions
.where( .where(
(element) => (element) => element.budgetCategoryId == ref.read(selectedCategory)!.id,
element.budgetCategoryId == ref.read(selectedCategory)!.id,
) )
.toList(); .toList();
} }
@@ -79,15 +75,15 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
break; break;
} }
WidgetsBinding.instance.addPostFrameCallback((_) => WidgetsBinding.instance
ref.read(transactionHistoryListProvider.notifier).state = transactions); .addPostFrameCallback((_) => ref.read(transactionHistoryListProvider.notifier).state = transactions);
return Scaffold( return Scaffold(
endDrawer: Drawer( endDrawer: Drawer(
backgroundColor: Styles.purpleNurple, backgroundColor: Styles.purpleNurple,
child: SafeArea( child: SafeArea(
child: Column( child: Column(
children: [ children: [
SizedBox(height: BuildMedia(context).height * 0.15), SizedBox(height: MediaQuery.of(context).size.height * 0.15),
DropdownButton<TransactionSort>( DropdownButton<TransactionSort>(
dropdownColor: Styles.lavender, dropdownColor: Styles.lavender,
value: ref.watch(selectedTransactionSortProvider), value: ref.watch(selectedTransactionSortProvider),
@@ -108,8 +104,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
.toList(), .toList(),
onChanged: (TransactionSort? value) { onChanged: (TransactionSort? value) {
if (value != null) { if (value != null) {
ref.read(selectedTransactionSortProvider.notifier).state = ref.read(selectedTransactionSortProvider.notifier).state = value;
value;
} }
}), }),
const SizedBox(height: 20), const SizedBox(height: 20),
@@ -137,8 +132,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
} }
}), }),
const SizedBox(height: 20), const SizedBox(height: 20),
if (ref.read(selectedTransactionSortProvider) == if (ref.read(selectedTransactionSortProvider) == TransactionSort.category)
TransactionSort.category)
DropdownButton<BudgetCategory>( DropdownButton<BudgetCategory>(
dropdownColor: Styles.lavender, dropdownColor: Styles.lavender,
value: ref.watch(selectedCategory), value: ref.watch(selectedCategory),
@@ -154,8 +148,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
width: 18, width: 18,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(color: Colors.black, width: 1.5),
color: Colors.black, width: 1.5),
color: e.color, color: e.color,
), ),
), ),
@@ -186,9 +179,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 8.0, top: 16.0), padding: const EdgeInsets.only(left: 8.0, top: 16.0),
child: IconButton( child: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)),
icon: const Icon(Icons.chevron_left),
onPressed: () => Navigator.pop(context)),
), ),
), ),
const Center( const Center(
@@ -201,14 +192,11 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0, top: 16.0), padding: const EdgeInsets.only(left: 8.0, top: 16.0),
child: IconButton( child: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)),
icon: const Icon(Icons.chevron_left),
onPressed: () => Navigator.pop(context)),
), ),
const Spacer(), const Spacer(),
const Padding( const Padding(
padding: padding: EdgeInsets.symmetric(vertical: 18.0, horizontal: 0.0),
EdgeInsets.symmetric(vertical: 18.0, horizontal: 0.0),
child: Text( child: Text(
'Transaction History', 'Transaction History',
style: TextStyle(fontSize: 28), style: TextStyle(fontSize: 28),
@@ -245,8 +233,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
} }
void toggleDrawer() { void toggleDrawer() {
if (scaffoldKey.currentState != null && if (scaffoldKey.currentState != null && scaffoldKey.currentState!.isDrawerOpen) {
scaffoldKey.currentState!.isDrawerOpen) {
scaffoldKey.currentState!.openDrawer(); scaffoldKey.currentState!.openDrawer();
} else if (scaffoldKey.currentState != null) { } else if (scaffoldKey.currentState != null) {
scaffoldKey.currentState!.openEndDrawer(); scaffoldKey.currentState!.openEndDrawer();
@@ -292,8 +279,7 @@ final selectedTransactionSortProvider = StateProvider<TransactionSort>(
(ref) => TransactionSort.all, (ref) => TransactionSort.all,
); );
final selectedSortDateProvider = final selectedSortDateProvider = StateProvider<SortDate>((ref) => SortDate.decending);
StateProvider<SortDate>((ref) => SortDate.decending);
final transactionHistoryListProvider = StateProvider<List<Transaction>>( final transactionHistoryListProvider = StateProvider<List<Transaction>>(
(ref) => [], (ref) => [],
@@ -1,7 +1,6 @@
import 'package:colorful_print/colorful_print.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:helpers/helpers/print.dart';
import 'package:rluv/global/styles.dart'; import 'package:rluv/global/styles.dart';
import 'package:rluv/models/budget.dart'; import 'package:rluv/models/budget.dart';
import 'package:rluv/models/budget_category_model.dart'; import 'package:rluv/models/budget_category_model.dart';
@@ -17,12 +16,10 @@ class BudgetCategoryDialog extends ConsumerStatefulWidget {
final BudgetCategory? category; final BudgetCategory? category;
@override @override
ConsumerState<BudgetCategoryDialog> createState() => ConsumerState<BudgetCategoryDialog> createState() => _AddBudgetCategoryDialogState();
_AddBudgetCategoryDialogState();
} }
class _AddBudgetCategoryDialogState class _AddBudgetCategoryDialogState extends ConsumerState<BudgetCategoryDialog> {
extends ConsumerState<BudgetCategoryDialog> {
late final Budget? budget; late final Budget? budget;
final categoryNameController = TextEditingController(); final categoryNameController = TextEditingController();
final amountController = TextEditingController(); final amountController = TextEditingController();
@@ -65,12 +62,11 @@ class _AddBudgetCategoryDialogState
return Container(); return Container();
} }
return SizedBox( return SizedBox(
width: BuildMedia(context).width * Styles.dialogScreenWidthFactor, width: MediaQuery.of(context).size.width * Styles.dialogScreenWidthFactor,
child: Stack( child: Stack(
children: [ children: [
Padding( Padding(
padding: padding: const EdgeInsets.symmetric(vertical: 18.0, horizontal: 32.0),
const EdgeInsets.symmetric(vertical: 18.0, horizontal: 32.0),
child: Form( child: Form(
key: formKey, key: formKey,
child: Column( child: Column(
@@ -78,9 +74,7 @@ class _AddBudgetCategoryDialogState
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 18.0), padding: const EdgeInsets.only(bottom: 18.0),
child: Text(widget.category == null child: Text(widget.category == null ? 'Add Category:' : 'Edit Category'),
? 'Add Category:'
: 'Edit Category'),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
@@ -149,8 +143,7 @@ class _AddBudgetCategoryDialogState
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 16.0),
vertical: 6.0, horizontal: 16.0),
child: SizedBox( child: SizedBox(
height: 76, height: 76,
child: ListView.builder( child: ListView.builder(
@@ -164,23 +157,21 @@ class _AddBudgetCategoryDialogState
} else { } else {
setState(() => selectedColorIndex = -1); setState(() => selectedColorIndex = -1);
} }
printBlue(selectedColorIndex); printColor(selectedColorIndex, textColor: TextColor.blue);
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: AnimatedContainer( child: AnimatedContainer(
decoration: selectedColorIndex == index decoration: selectedColorIndex == index
? BoxDecoration( ? BoxDecoration(
borderRadius: borderRadius: BorderRadius.circular(15.0),
BorderRadius.circular(15.0),
border: Border.all( border: Border.all(
color: Styles.washedStone, color: Styles.washedStone,
width: 2.0, width: 2.0,
), ),
) )
: BoxDecoration( : BoxDecoration(
borderRadius: borderRadius: BorderRadius.circular(5.0),
BorderRadius.circular(5.0),
border: Border.all( border: Border.all(
color: Colors.transparent, color: Colors.transparent,
width: 2.0, width: 2.0,
@@ -205,8 +196,7 @@ class _AddBudgetCategoryDialogState
decoration: BoxDecoration( decoration: BoxDecoration(
color: colors[index], color: colors[index],
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(color: Colors.black, width: 1.5),
color: Colors.black, width: 1.5),
), ),
), ),
], ],
@@ -227,8 +217,7 @@ class _AddBudgetCategoryDialogState
color: Styles.expensesRed, color: Styles.expensesRed,
text: 'DELETE', text: 'DELETE',
onPressed: () { onPressed: () {
if (formKey.currentState != null && if (formKey.currentState != null && formKey.currentState!.validate()) {
formKey.currentState!.validate()) {
removeCategory().then((success) { removeCategory().then((success) {
Navigator.pop(context); Navigator.pop(context);
if (success) { if (success) {
@@ -254,8 +243,7 @@ class _AddBudgetCategoryDialogState
color: Styles.lavender, color: Styles.lavender,
text: 'SAVE', text: 'SAVE',
onPressed: () { onPressed: () {
if (formKey.currentState != null && if (formKey.currentState != null && formKey.currentState!.validate()) {
formKey.currentState!.validate()) {
submitCategory(colors[selectedColorIndex]).then((_) { submitCategory(colors[selectedColorIndex]).then((_) {
Navigator.pop(context); Navigator.pop(context);
showSnack( showSnack(
@@ -282,7 +270,7 @@ class _AddBudgetCategoryDialogState
Future submitCategory(Color categoryColor) async { Future submitCategory(Color categoryColor) async {
if (formKey.currentState != null && !formKey.currentState!.validate()) { if (formKey.currentState != null && !formKey.currentState!.validate()) {
printPink('Failed validation'); printColor('Failed validation', textColor: TextColor.red);
return; return;
} }
Map<String, dynamic>? budgetData; Map<String, dynamic>? budgetData;
@@ -296,58 +284,41 @@ class _AddBudgetCategoryDialogState
name: categoryNameController.text, name: categoryNameController.text,
); );
budgetData = await ref budgetData = await ref.read(apiProvider.notifier).post(path: 'budget_category', data: newBudget.toJson());
.read(apiProvider.notifier)
.post(path: 'budget_category', data: newBudget.toJson());
success = budgetData != null ? budgetData['success'] as bool : false; success = budgetData != null ? budgetData['success'] as bool : false;
if (success) { if (success) {
ref ref.read(dashboardProvider.notifier).add({'budget_categories': budgetData});
.read(dashboardProvider.notifier)
.add({'budget_categories': budgetData});
} }
} else { } else {
final newBudget = final newBudget = BudgetCategory.copyWith(category: widget.category!, data: {
BudgetCategory.copyWith(category: widget.category!, data: {
'amount': double.parse(amountController.text), 'amount': double.parse(amountController.text),
'color': categoryColor, 'color': categoryColor,
'name': categoryNameController.text 'name': categoryNameController.text
}); });
budgetData = await ref budgetData = await ref.read(apiProvider.notifier).put(path: 'budget_category', data: newBudget.toJson());
.read(apiProvider.notifier)
.put(path: 'budget_category', data: newBudget.toJson());
success = budgetData != null ? budgetData['success'] as bool : false; success = budgetData != null ? budgetData['success'] as bool : false;
if (success) { if (success) {
ref ref.read(dashboardProvider.notifier).update({'budget_categories': budgetData});
.read(dashboardProvider.notifier)
.update({'budget_categories': budgetData});
} }
} }
if (success) { if (success) {
showSnack( showSnack(
ref: ref, ref: ref,
text: widget.category == null text: widget.category == null ? 'Added budget category!' : 'Updated category!',
? 'Added budget category!'
: 'Updated category!',
type: SnackType.error); type: SnackType.error);
} else { } else {
showSnack( showSnack(
ref: ref, ref: ref,
text: widget.category == null text: widget.category == null ? 'Could not add budget category' : 'Could not update category',
? 'Could not add budget category'
: 'Could not update category',
type: SnackType.error); type: SnackType.error);
} }
} }
Future<bool> removeCategory() async { Future<bool> removeCategory() async {
final res = await ref final res = await ref.read(apiProvider.notifier).delete(path: 'budget_category', data: {'id': widget.category!.id});
.read(apiProvider.notifier)
.delete(path: 'budget_category', data: {'id': widget.category!.id});
final success = res != null ? res['success'] as bool : false; final success = res != null ? res['success'] as bool : false;
if (success) { if (success) {
ref ref.read(dashboardProvider.notifier).removeWithId('budget_categories', widget.category!.id!);
.read(dashboardProvider.notifier)
.removeWithId('budget_categories', widget.category!.id!);
} }
return success; return success;
} }
@@ -1,7 +1,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:rluv/global/utils.dart'; import 'package:rluv/global/utils.dart';
import '../../../global/api.dart'; import '../../../global/api.dart';
@@ -18,8 +17,7 @@ class TransactionDialog extends ConsumerStatefulWidget {
final Transaction? transaction; final Transaction? transaction;
@override @override
ConsumerState<TransactionDialog> createState() => ConsumerState<TransactionDialog> createState() => _AddTransactionDialogState();
_AddTransactionDialogState();
} }
class _AddTransactionDialogState extends ConsumerState<TransactionDialog> { class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
@@ -37,8 +35,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
@override @override
void initState() { void initState() {
if (widget.transaction != null) { if (widget.transaction != null) {
amountController = amountController = TextEditingController(text: widget.transaction!.amount.toString());
TextEditingController(text: widget.transaction!.amount.toString());
memoController = TextEditingController(text: widget.transaction!.memo); memoController = TextEditingController(text: widget.transaction!.memo);
transactionType = widget.transaction!.type; transactionType = widget.transaction!.type;
selectedDate = widget.transaction!.date; selectedDate = widget.transaction!.date;
@@ -53,8 +50,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
} }
final u = ref.read(userProvider); final u = ref.read(userProvider);
if (u == null) { if (u == null) {
WidgetsBinding.instance.addPostFrameCallback( WidgetsBinding.instance.addPostFrameCallback((_) => ref.read(jwtProvider.notifier).revokeToken());
(_) => ref.read(jwtProvider.notifier).revokeToken());
} else { } else {
user = u; user = u;
} }
@@ -65,10 +61,9 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (user == null) return Container(); if (user == null) return Container();
final List<BudgetCategory> budgetCategories = final List<BudgetCategory> budgetCategories = ref.read(budgetCategoriesProvider);
ref.read(budgetCategoriesProvider);
return SizedBox( return SizedBox(
width: BuildMedia(context).width * Styles.dialogScreenWidthFactor, width: MediaQuery.of(context).size.width * Styles.dialogScreenWidthFactor,
child: budgetCategories.isEmpty child: budgetCategories.isEmpty
? const Padding( ? const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
@@ -91,25 +86,21 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
onTap: transactionType == TransactionType.expense onTap: transactionType == TransactionType.expense
? null ? null
: () { : () {
setState(() => transactionType = setState(() => transactionType = TransactionType.expense);
TransactionType.expense);
}, },
child: AnimatedContainer( child: AnimatedContainer(
height: 38, height: 38,
width: 80, width: 80,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8.0), topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0)),
topRight: Radius.circular(8.0)), color: transactionType == TransactionType.expense
color: transactionType ==
TransactionType.expense
? Styles.lavender ? Styles.lavender
: Styles.washedStone), : Styles.washedStone),
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text('Expense', child: Text('Expense', style: TextStyle(fontSize: 16)),
style: TextStyle(fontSize: 16)),
), ),
), ),
), ),
@@ -117,25 +108,20 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
onTap: transactionType == TransactionType.income onTap: transactionType == TransactionType.income
? null ? null
: () { : () {
setState(() => transactionType = setState(() => transactionType = TransactionType.income);
TransactionType.income);
}, },
child: AnimatedContainer( child: AnimatedContainer(
height: 38, height: 38,
width: 80, width: 80,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8.0), topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0)),
topRight: Radius.circular(8.0)),
color: color:
transactionType == TransactionType.income transactionType == TransactionType.income ? Styles.lavender : Styles.washedStone),
? Styles.lavender
: Styles.washedStone),
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text('Income', child: Text('Income', style: TextStyle(fontSize: 16)),
style: TextStyle(fontSize: 16)),
), ),
), ),
), ),
@@ -208,9 +194,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
width: 18, width: 18,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(color: Colors.black, width: 1.5),
color: Colors.black,
width: 1.5),
color: e.color, color: e.color,
), ),
), ),
@@ -226,8 +210,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
if (kDebugMode) { if (kDebugMode) {
print('${value.name} selected'); print('${value.name} selected');
} }
setState(() => setState(() => selectedBudgetCategory = value);
selectedBudgetCategory = value);
} }
}, },
), ),
@@ -247,7 +230,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
), ),
), ),
Container( Container(
width: BuildMedia(context).width * 0.65, width: MediaQuery.of(context).size.width * 0.65,
height: 100, height: 100,
decoration: Styles.boxLavenderBubble, decoration: Styles.boxLavenderBubble,
child: TextFormField( child: TextFormField(
@@ -269,9 +252,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
Navigator.pop(context); Navigator.pop(context);
showSnack( showSnack(
ref: ref, ref: ref,
text: widget.transaction != null text: widget.transaction != null ? 'Transaction updated!' : 'Transaction added!',
? 'Transaction updated!'
: 'Transaction added!',
type: SnackType.success, type: SnackType.success,
); );
}), }),
@@ -289,9 +270,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
data: Transaction.copyWith(widget.transaction!, { data: Transaction.copyWith(widget.transaction!, {
'memo': memoController.text.isNotEmpty ? memoController.text : null, 'memo': memoController.text.isNotEmpty ? memoController.text : null,
'amount': double.parse(amountController.text), 'amount': double.parse(amountController.text),
'budget_category_id': transactionType == TransactionType.income 'budget_category_id': transactionType == TransactionType.income ? null : selectedBudgetCategory.id,
? null
: selectedBudgetCategory.id,
}).toJson()); }).toJson());
} else { } else {
data = await ref.read(apiProvider.notifier).post( data = await ref.read(apiProvider.notifier).post(
@@ -299,15 +278,11 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
data: Transaction( data: Transaction(
amount: double.parse(amountController.text), amount: double.parse(amountController.text),
createdByUserId: user!.id!, createdByUserId: user!.id!,
budgetCategoryId: transactionType == TransactionType.income budgetCategoryId: transactionType == TransactionType.income ? null : selectedBudgetCategory.id,
? null
: selectedBudgetCategory.id,
budgetId: user!.budgetId, budgetId: user!.budgetId,
date: DateTime.now(), date: DateTime.now(),
type: transactionType, type: transactionType,
memo: memoController.text.isNotEmpty memo: memoController.text.isNotEmpty ? memoController.text : null)
? memoController.text
: null)
.toJson()); .toJson());
} }
final success = data != null ? data['success'] as bool : false; final success = data != null ? data['success'] as bool : false;
@@ -320,9 +295,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
} else { } else {
showSnack( showSnack(
ref: ref, ref: ref,
text: widget.transaction != null text: widget.transaction != null ? 'Failed to edit transaction' : 'Failed to add transaction',
? 'Failed to edit transaction'
: 'Failed to add transaction',
type: SnackType.error); type: SnackType.error);
} }
} }
@@ -1,7 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:helpers/helpers/print.dart';
import 'package:rluv/features/budget/widgets/add_budget_category_dialog.dart'; import 'package:rluv/features/budget/widgets/add_budget_category_dialog.dart';
import 'package:rluv/global/utils.dart'; import 'package:rluv/global/utils.dart';
import 'package:rluv/models/budget_category_model.dart'; import 'package:rluv/models/budget_category_model.dart';
@@ -45,8 +44,7 @@ class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
} }
}); });
final innerHeight = widget.height - widget.innerPadding * 2; final innerHeight = widget.height - widget.innerPadding * 2;
final isBright = final isBright = getBrightness(widget.budgetCategory.color) == Brightness.light;
getBrightness(widget.budgetCategory.color) == Brightness.light;
final textStyle = TextStyle( final textStyle = TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -155,7 +153,6 @@ class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
if (!name.contains(' ') || name.indexOf(' ') == name.length - 1) { if (!name.contains(' ') || name.indexOf(' ') == name.length - 1) {
return name; return name;
} }
printLime('here');
final words = name.split(' '); final words = name.split(' ');
int index = 0; int index = 0;
String firstLine = words[index]; String firstLine = words[index];
@@ -1,14 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:helpers/helpers.dart';
import 'package:rluv/global/styles.dart'; import 'package:rluv/global/styles.dart';
import 'package:rluv/global/utils.dart'; import 'package:rluv/global/utils.dart';
class BudgetNetBar extends StatelessWidget { class BudgetNetBar extends StatelessWidget {
const BudgetNetBar( const BudgetNetBar({super.key, required this.isPositive, required this.net, required this.expected});
{super.key,
required this.isPositive,
required this.net,
required this.expected});
final bool isPositive; final bool isPositive;
final double net; final double net;
@@ -16,7 +11,7 @@ class BudgetNetBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screenWidth = BuildMedia(context).width; final screenWidth = MediaQuery.of(context).size.width;
return Container( return Container(
width: screenWidth * 0.85, width: screenWidth * 0.85,
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -25,8 +20,7 @@ class BudgetNetBar extends StatelessWidget {
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0), padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0),
child: child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text( Text(
isPositive ? 'Income' : 'Expenses', isPositive ? 'Income' : 'Expenses',
style: const TextStyle( style: const TextStyle(
@@ -35,9 +29,7 @@ class BudgetNetBar extends StatelessWidget {
), ),
Text( Text(
'${net.currency()} / ${expected.currency()}', '${net.currency()} / ${expected.currency()}',
style: TextStyle( style: TextStyle(fontSize: 20, color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
fontSize: 20,
color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
), ),
]), ]),
), ),
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:rluv/features/budget/screens/transactions_listview.dart'; import 'package:rluv/features/budget/screens/transactions_listview.dart';
import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart'; import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
@@ -19,8 +18,7 @@ class TransactionListItem extends ConsumerStatefulWidget {
final int index; final int index;
@override @override
ConsumerState<TransactionListItem> createState() => ConsumerState<TransactionListItem> createState() => _TransactionListItemState();
_TransactionListItemState();
} }
class _TransactionListItemState extends ConsumerState<TransactionListItem> { class _TransactionListItemState extends ConsumerState<TransactionListItem> {
@@ -54,17 +52,13 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 8.0, left: 8.0, bottom: 8.0), padding: const EdgeInsets.only(top: 8.0, left: 8.0, bottom: 8.0),
child: ClipRRect( child: ClipRRect(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)),
topLeft: Radius.circular(10.0),
bottomLeft: Radius.circular(10.0)),
child: AnimatedContainer( child: AnimatedContainer(
curve: Curves.easeOut, curve: Curves.easeOut,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
height: cardHeight, height: cardHeight,
decoration: const BoxDecoration( decoration: const BoxDecoration(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)),
topLeft: Radius.circular(10.0),
bottomLeft: Radius.circular(10.0)),
color: Styles.washedStone, color: Styles.washedStone,
), ),
child: Row( child: Row(
@@ -74,19 +68,16 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
height: cardHeight, height: cardHeight,
width: 6, width: 6,
color: transaction!.type == TransactionType.income color: transaction!.type == TransactionType.income ? Styles.incomeBlue : Styles.expensesOrange),
? Styles.incomeBlue
: Styles.expensesOrange),
SizedBox( SizedBox(
width: BuildMedia(context).width * 0.65, width: MediaQuery.of(context).size.width * 0.65,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(DateFormat('EEE MMM d, h:mm a') Text(DateFormat('EEE MMM d, h:mm a').format(transaction!.date)),
.format(transaction!.date)),
Row( Row(
children: [ children: [
const SizedBox( const SizedBox(
@@ -101,9 +92,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
), ),
], ],
Text( Text(
transaction!.type == TransactionType.income transaction!.type == TransactionType.income ? 'Income' : budgetCategory!.name,
? 'Income'
: budgetCategory!.name,
style: const TextStyle(fontSize: 20), style: const TextStyle(fontSize: 20),
), ),
], ],
@@ -125,9 +114,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
transaction!.amount.currency(), transaction!.amount.currency(),
style: TextStyle( style: TextStyle(
fontSize: 24, fontSize: 24,
color: transaction!.type == TransactionType.income color: transaction!.type == TransactionType.income ? Styles.incomeGreen : Styles.expensesRed),
? Styles.incomeGreen
: Styles.expensesRed),
), ),
if (showDetails) ...[ if (showDetails) ...[
IconButton( IconButton(
@@ -140,8 +127,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
builder: (context) => Dialog( builder: (context) => Dialog(
backgroundColor: Styles.dialogColor, backgroundColor: Styles.dialogColor,
shape: Styles.dialogShape, shape: Styles.dialogShape,
child: child: TransactionDialog(transaction: transaction),
TransactionDialog(transaction: transaction),
), ),
); );
}, },
@@ -182,21 +168,14 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
} }
Future deleteTransaction() async { Future deleteTransaction() async {
final res = await ref final res = await ref.read(apiProvider.notifier).delete(path: 'transaction', data: {'id': transaction!.id});
.read(apiProvider.notifier)
.delete(path: 'transaction', data: {'id': transaction!.id});
final success = res != null ? res['success'] as bool : false; final success = res != null ? res['success'] as bool : false;
if (success) { if (success) {
ref ref.read(dashboardProvider.notifier).removeWithId('transactions', transaction!.id!);
.read(dashboardProvider.notifier)
.removeWithId('transactions', transaction!.id!);
showSnack(ref: ref, text: 'Transaction removed', type: SnackType.success); showSnack(ref: ref, text: 'Transaction removed', type: SnackType.success);
} else { } else {
showSnack( showSnack(ref: ref, text: 'Could not delete transaction', type: SnackType.error);
ref: ref,
text: 'Could not delete transaction',
type: SnackType.error);
} }
} }
} }
+20 -53
View File
@@ -1,8 +1,7 @@
import 'package:colorful_print/colorful_print.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:helpers/helpers/print.dart';
import 'package:rluv/global/utils.dart'; import 'package:rluv/global/utils.dart';
import 'package:rluv/models/shared_note.dart'; import 'package:rluv/models/shared_note.dart';
@@ -22,7 +21,7 @@ class SharedNotesScreen extends ConsumerStatefulWidget {
class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> { class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
final sharedNotes = ref.watch(sharedNotesProvider); final sharedNotes = ref.watch(sharedNotesProvider);
return Column( return Column(
children: [ children: [
@@ -47,14 +46,10 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
), ),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final note = sharedNotes[index]; final note = sharedNotes[index];
final colorBrightness = note.color == null final colorBrightness = note.color == null ? Brightness.light : getBrightness(note.color!);
? Brightness.light
: getBrightness(note.color!);
final textStyle = TextStyle( final textStyle = TextStyle(
fontSize: 16.0, fontSize: 16.0,
color: colorBrightness == Brightness.light color: colorBrightness == Brightness.light ? Colors.black54 : Colors.white70,
? Colors.black54
: Colors.white70,
); );
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@@ -67,14 +62,10 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
children: [ children: [
FittedBox( FittedBox(child: Text(note.title, style: const TextStyle(fontSize: 20))),
child: Text(note.title,
style: const TextStyle(fontSize: 20))),
Flexible( Flexible(
child: Text( child: Text(
note.content.length > 80 note.content.length > 80 ? "${note.content.substring(0, 75)}..." : note.content,
? "${note.content.substring(0, 75)}..."
: note.content,
style: textStyle, style: textStyle,
), ),
), ),
@@ -93,9 +84,7 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return Padding( return Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
bottom:
MediaQuery.of(context).viewInsets.bottom),
child: NoteBottomSheet( child: NoteBottomSheet(
index: index, index: index,
), ),
@@ -121,8 +110,7 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return Padding( return Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
bottom: MediaQuery.of(context).viewInsets.bottom),
child: const NoteBottomSheet( child: const NoteBottomSheet(
index: null, index: null,
), ),
@@ -182,19 +170,14 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screen = BuildMedia(context).size; final screen = MediaQuery.of(context).size;
return Container( return Container(
width: screen.width, width: screen.width,
decoration: BoxDecoration( decoration: BoxDecoration(
color: newNote.color ?? Styles.washedStone, color: newNote.color ?? Styles.washedStone,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
boxShadow: const [ boxShadow: const [
BoxShadow( BoxShadow(color: Colors.black26, spreadRadius: 5.0, blurRadius: 2.0, offset: Offset(0, -2))
color: Colors.black26,
spreadRadius: 5.0,
blurRadius: 2.0,
offset: Offset(0, -2))
]), ]),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@@ -218,8 +201,7 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
// decoration: Styles.inputLavenderBubble(), // decoration: Styles.inputLavenderBubble(),
), ),
Padding( Padding(
padding: padding: const EdgeInsets.symmetric(vertical: 28.0, horizontal: 36.0),
const EdgeInsets.symmetric(vertical: 28.0, horizontal: 36.0),
child: UiButton( child: UiButton(
onPressed: !noteChanged(oldNote, newNote) onPressed: !noteChanged(oldNote, newNote)
? null ? null
@@ -229,41 +211,26 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
try { try {
Response? res; Response? res;
if (widget.index == null) { if (widget.index == null) {
res = await ref res = await ref.read(apiProvider).post('shared_note', data: newNote.toJson());
.read(apiProvider)
.post('shared_note', data: newNote.toJson());
} else { } else {
res = await ref res = await ref.read(apiProvider).put('shared_note', data: newNote.toJson());
.read(apiProvider)
.put('shared_note', data: newNote.toJson());
} }
if (res.data != null && res.data['success']) { if (res.data != null && res.data['success']) {
if (widget.index == null) { if (widget.index == null) {
ref ref.read(dashboardProvider.notifier).add({'shared_notes': res.data});
.read(dashboardProvider.notifier)
.add({'shared_notes': res.data});
} else { } else {
ref ref.read(dashboardProvider.notifier).update({'shared_notes': res.data});
.read(dashboardProvider.notifier)
.update({'shared_notes': res.data});
} }
showSnack( showSnack(ref: ref, text: 'Added note', type: SnackType.success);
ref: ref,
text: 'Added note',
type: SnackType.success);
} else { } else {
showSnack( showSnack(
ref: ref, ref: ref,
text: res.data['message'] ?? text: res.data['message'] ?? 'Unexpected error occurred',
'Unexpected error occurred',
type: SnackType.error); type: SnackType.error);
} }
} catch (err) { } catch (err) {
showSnack( showSnack(ref: ref, text: 'Unexpected error occurred', type: SnackType.error);
ref: ref, printColor(err, textColor: TextColor.red);
text: 'Unexpected error occurred',
type: SnackType.error);
printRed(err);
} }
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
Navigator.pop(context); Navigator.pop(context);
+19 -27
View File
@@ -1,9 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'package:colorful_print/colorful_print.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/print.dart';
import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:rluv/global/store.dart'; import 'package:rluv/global/store.dart';
@@ -11,7 +11,7 @@ import '../models/token.dart';
final tokenProvider = StateProvider<Token?>((ref) { final tokenProvider = StateProvider<Token?>((ref) {
final jwt = ref.watch(jwtProvider); final jwt = ref.watch(jwtProvider);
printLime('Current token: $jwt'); printColor('Current token: $jwt', textColor: TextColor.green);
if (jwt == null) return null; if (jwt == null) return null;
try { try {
return Token.fromJson(JwtDecoder.decode(jwt)); return Token.fromJson(JwtDecoder.decode(jwt));
@@ -37,12 +37,12 @@ class _JwtNotifier extends StateNotifier<String?> {
void setToken(String jwt) { void setToken(String jwt) {
state = jwt; state = jwt;
printCyan('Loaded jwt into client: $jwt'); printColor('Loaded jwt into client: $jwt', textColor: TextColor.cyan);
ref.read(prefsProvider)?.setString('jwt', jwt); ref.read(prefsProvider)?.setString('jwt', jwt);
} }
void revokeToken() { void revokeToken() {
printCyan('jwt token revoked'); printColor('jwt token revoked', textColor: TextColor.cyan);
state = null; state = null;
ref.read(prefsProvider)?.remove('jwt'); ref.read(prefsProvider)?.remove('jwt');
} }
@@ -58,8 +58,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
// dio.options.baseUrl = "http://localhost:8081/"; // dio.options.baseUrl = "http://localhost:8081/";
dio.options.baseUrl = "https://rluv.fosscat.com/"; dio.options.baseUrl = "https://rluv.fosscat.com/";
dio.interceptors.addAll([ dio.interceptors.addAll([
InterceptorsWrapper(onRequest: InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
(RequestOptions options, RequestInterceptorHandler handler) {
final jwt = ref.read(jwtProvider); final jwt = ref.read(jwtProvider);
if (jwt != null) { if (jwt != null) {
options.headers['token'] = jwt; options.headers['token'] = jwt;
@@ -69,12 +68,10 @@ class _ApiNotifier extends StateNotifier<Dio> {
if (response.statusCode != null) { if (response.statusCode != null) {
if (response.statusCode == 200) { if (response.statusCode == 200) {
try { try {
if ((response.data as Map<String, dynamic>) if ((response.data as Map<String, dynamic>).containsKey('success')) {
.containsKey('success')) {
if (!response.data['success']) return handler.next(response); if (!response.data['success']) return handler.next(response);
} }
if ((response.data as Map<String, dynamic>) if ((response.data as Map<String, dynamic>).containsKey('token')) {
.containsKey('token')) {
final jwt = response.data['token']; final jwt = response.data['token'];
if (jwt != null) { if (jwt != null) {
ref.read(jwtProvider.notifier).setToken(jwt); ref.read(jwtProvider.notifier).setToken(jwt);
@@ -83,7 +80,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
} }
} }
} catch (err) { } catch (err) {
printRed('Error in interceptor for token: $err'); printColor('Error in interceptor for token: $err', textColor: TextColor.red);
return handler.next(response); return handler.next(response);
} }
} }
@@ -115,8 +112,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
} }
} }
Future<Map<String, dynamic>?> put( Future<Map<String, dynamic>?> put({required String path, Object? data}) async {
{required String path, Object? data}) async {
try { try {
final res = await dio.put(path, data: data); final res = await dio.put(path, data: data);
@@ -129,8 +125,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
} }
} }
Future<Map<String, dynamic>?> post( Future<Map<String, dynamic>?> post({required String path, Object? data}) async {
{required String path, Object? data}) async {
try { try {
final res = await dio.post(path, data: data); final res = await dio.post(path, data: data);
@@ -143,8 +138,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
} }
} }
Future<Map<String, dynamic>?> delete( Future<Map<String, dynamic>?> delete({required String path, Object? data}) async {
{required String path, Object? data}) async {
try { try {
final res = await dio.delete(path, data: data); final res = await dio.delete(path, data: data);
@@ -162,8 +156,7 @@ class _LoggingInterceptor extends Interceptor {
_LoggingInterceptor(); _LoggingInterceptor();
@override @override
Future onRequest( Future onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
RequestOptions options, RequestInterceptorHandler handler) async {
logPrint('///*** REQUEST ***\\\\\\'); logPrint('///*** REQUEST ***\\\\\\');
printKV('URI', options.uri); printKV('URI', options.uri);
printKV('METHOD', options.method); printKV('METHOD', options.method);
@@ -177,7 +170,7 @@ class _LoggingInterceptor extends Interceptor {
@override @override
void onError(DioException err, ErrorInterceptorHandler handler) { void onError(DioException err, ErrorInterceptorHandler handler) {
printRed('///*** ERROR RESPONSE ***\\\\\\'); printColor('///*** ERROR RESPONSE ***\\\\\\', textColor: TextColor.red);
logPrint('URI: ${err.requestOptions.uri}'); logPrint('URI: ${err.requestOptions.uri}');
if (err.response != null) { if (err.response != null) {
logPrint('STATUS CODE: ${err.response?.statusCode?.toString()}'); logPrint('STATUS CODE: ${err.response?.statusCode?.toString()}');
@@ -192,8 +185,7 @@ class _LoggingInterceptor extends Interceptor {
} }
@override @override
Future onResponse( Future onResponse(Response response, ResponseInterceptorHandler handler) async {
Response response, ResponseInterceptorHandler handler) async {
logPrint('///*** RESPONSE ***\\\\\\'); logPrint('///*** RESPONSE ***\\\\\\');
printKV('URI', response.requestOptions.uri); printKV('URI', response.requestOptions.uri);
printKV('STATUS CODE', response.statusCode ?? ''); printKV('STATUS CODE', response.statusCode ?? '');
@@ -206,7 +198,7 @@ class _LoggingInterceptor extends Interceptor {
void printKV(String key, Object v) { void printKV(String key, Object v) {
if (kDebugMode) { if (kDebugMode) {
printOrange('$key: $v'); printColor('$key: $v', textColor: TextColor.orange);
} }
} }
@@ -215,21 +207,21 @@ class _LoggingInterceptor extends Interceptor {
final data = (s as Map<String, dynamic>?); final data = (s as Map<String, dynamic>?);
if (kDebugMode) { if (kDebugMode) {
if (data == null) { if (data == null) {
printAmber({}); printColor({}, textColor: TextColor.yellow);
return; return;
} }
JsonEncoder encoder = const JsonEncoder.withIndent(' '); JsonEncoder encoder = const JsonEncoder.withIndent(' ');
String prettyprint = encoder.convert(s); String prettyprint = encoder.convert(s);
printAmber(prettyprint); printColor(prettyprint, textColor: TextColor.yellow);
} }
} catch (_) { } catch (_) {
printAmber(s); printColor(s, textColor: TextColor.yellow);
} }
} }
void logPrint(String s) { void logPrint(String s) {
if (kDebugMode) { if (kDebugMode) {
printOrange(s); printColor(s, textColor: TextColor.yellow);
} }
} }
} }
+14 -22
View File
@@ -1,8 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:colorful_print/colorful_print.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/print.dart';
import 'package:rluv/global/api.dart'; import 'package:rluv/global/api.dart';
import 'package:rluv/models/budget.dart'; import 'package:rluv/models/budget.dart';
import 'package:rluv/models/budget_category_model.dart'; import 'package:rluv/models/budget_category_model.dart';
@@ -13,8 +13,7 @@ import '../models/shared_note.dart';
import '../models/transaction_model.dart'; import '../models/transaction_model.dart';
import '../models/user.dart'; import '../models/user.dart';
StateProvider<SharedPreferences?> prefsProvider = StateProvider<SharedPreferences?> prefsProvider = StateProvider<SharedPreferences?>((ref) => null);
StateProvider<SharedPreferences?>((ref) => null);
// final StateProvider<Token?> tokenProvider = StateProvider<Token?>((ref) { // final StateProvider<Token?> tokenProvider = StateProvider<Token?>((ref) {
// // final tokenStr = prefs.getString('jwt'); // // final tokenStr = prefs.getString('jwt');
@@ -42,8 +41,7 @@ final Provider<FamilyModel?> familyProvider = Provider<FamilyModel?>(
}, },
); );
final Provider<List<BudgetCategory>> budgetCategoriesProvider = final Provider<List<BudgetCategory>> budgetCategoriesProvider = Provider<List<BudgetCategory>>((ref) {
Provider<List<BudgetCategory>>((ref) {
final dash = ref.watch(dashboardProvider); final dash = ref.watch(dashboardProvider);
if (dash == null) return []; if (dash == null) return [];
final categoriesData = dash['budget_categories'] as List<dynamic>; final categoriesData = dash['budget_categories'] as List<dynamic>;
@@ -55,7 +53,7 @@ final Provider<List<BudgetCategory>> budgetCategoriesProvider =
final prefs = ref.read(prefsProvider); final prefs = ref.read(prefsProvider);
final budgetJson = jsonEncode({'budget_categories': categoriesData}); final budgetJson = jsonEncode({'budget_categories': categoriesData});
printBlue('updated prefs stored categories'); printColor('updated prefs stored categories', textColor: TextColor.blue);
prefs?.setString('budget_categories', budgetJson); prefs?.setString('budget_categories', budgetJson);
return categories; return categories;
@@ -71,8 +69,7 @@ final Provider<Budget?> budgetProvider = Provider<Budget?>(
}, },
); );
final Provider<List<Transaction>> transactionsProvider = final Provider<List<Transaction>> transactionsProvider = Provider<List<Transaction>>((ref) {
Provider<List<Transaction>>((ref) {
final dash = ref.watch(dashboardProvider); final dash = ref.watch(dashboardProvider);
if (dash == null) return []; if (dash == null) return [];
final transactions = dash['transactions'] as List<dynamic>; final transactions = dash['transactions'] as List<dynamic>;
@@ -83,8 +80,7 @@ final Provider<List<Transaction>> transactionsProvider =
.toList(); .toList();
}); });
final Provider<List<SharedNote>> sharedNotesProvider = final Provider<List<SharedNote>> sharedNotesProvider = Provider<List<SharedNote>>(
Provider<List<SharedNote>>(
(ref) { (ref) {
final dash = ref.watch(dashboardProvider); final dash = ref.watch(dashboardProvider);
if (dash == null) return []; if (dash == null) return [];
@@ -97,8 +93,7 @@ final Provider<List<SharedNote>> sharedNotesProvider =
}, },
); );
final dashboardProvider = final dashboardProvider = StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
(ref) { (ref) {
return DashBoardStateNotifier(ref); return DashBoardStateNotifier(ref);
}, },
@@ -119,10 +114,10 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
); );
final token = ref.read(tokenProvider); final token = ref.read(tokenProvider);
if (token?.familyId == null) { if (token?.familyId == null) {
printPink('No token, cannot fetch dashboard'); printColor('No token, cannot fetch dashboard', textColor: TextColor.red);
return; return;
} }
printAmber('Fetching dashboard'); printColor('Fetching dashboard', textColor: TextColor.yellow);
state = await ref.read(apiProvider.notifier).get("dashboard"); state = await ref.read(apiProvider.notifier).get("dashboard");
WidgetsBinding.instance.addPostFrameCallback( WidgetsBinding.instance.addPostFrameCallback(
(_) => ref.read(loadingStateProvider.notifier).state = false, (_) => ref.read(loadingStateProvider.notifier).state = false,
@@ -131,7 +126,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
void update(Map<String, dynamic> data) { void update(Map<String, dynamic> data) {
if (state == null) { if (state == null) {
printPink('Cant update data, state is null'); printColor('Cant update data, state is null', textColor: TextColor.red);
return; return;
} }
if (data.keys.length != 1 || data.values.length != 1) { if (data.keys.length != 1 || data.values.length != 1) {
@@ -149,9 +144,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
) )
.toList(); .toList();
subStateListObj.removeWhere( subStateListObj.removeWhere(
(element) => (element) => element['id'] == (data.values.first as Map<String, dynamic>)['id'],
element['id'] ==
(data.values.first as Map<String, dynamic>)['id'],
); );
subStateListObj.add(data.values.first); subStateListObj.add(data.values.first);
@@ -167,7 +160,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
void add(Map<String, dynamic> data) { void add(Map<String, dynamic> data) {
if (state == null) { if (state == null) {
printPink('Cant add data, state is null'); printColor('Cant add data, state is null', textColor: TextColor.red);
return; return;
} }
if (data.keys.length != 1 || data.values.length != 1) { if (data.keys.length != 1 || data.values.length != 1) {
@@ -192,7 +185,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
void removeWithId(String stateKey, int id) { void removeWithId(String stateKey, int id) {
if (state == null) { if (state == null) {
printPink('Cant remove data, state is null'); printColor('Cant remove data, state is null', textColor: TextColor.red);
return; return;
} }
switch (stateKey) { switch (stateKey) {
@@ -201,8 +194,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
case 'shared_noted': case 'shared_noted':
final subStateList = state![stateKey] as List<dynamic>; final subStateList = state![stateKey] as List<dynamic>;
final newState = state; final newState = state;
subStateList subStateList.removeWhere((e) => (e as Map<String, dynamic>)['id'] == id);
.removeWhere((e) => (e as Map<String, dynamic>)['id'] == id);
newState![stateKey] = subStateList; newState![stateKey] = subStateList;
state = {...newState}; state = {...newState};
// printBlue(state); // printBlue(state);
+11 -19
View File
@@ -1,9 +1,9 @@
import 'dart:math'; import 'dart:math';
import 'package:colorful_print/colorful_print.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/print.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:rluv/global/styles.dart'; import 'package:rluv/global/styles.dart';
import 'package:rluv/main.dart'; import 'package:rluv/main.dart';
@@ -20,20 +20,16 @@ bool boolFromJson(int value) => value == 1;
int boolToJson(bool hide) => hide ? 1 : 0; int boolToJson(bool hide) => hide ? 1 : 0;
String colorToJson(Color color) => String colorToJson(Color color) => color.toString().split('(0x')[1].split(')')[0];
color.toString().split('(0x')[1].split(')')[0];
Color colorFromJson(String hex) => Color(int.parse(hex, radix: 16)); Color colorFromJson(String hex) => Color(int.parse(hex, radix: 16));
String? optionalColorToJson(Color? optionalColor) => optionalColor == null String? optionalColorToJson(Color? optionalColor) =>
? null optionalColor == null ? null : optionalColor.toString().split('(0x')[1].split(')')[0];
: optionalColor.toString().split('(0x')[1].split(')')[0];
Color? optionalColorFromJson(String? hex) => Color? optionalColorFromJson(String? hex) => hex == null ? null : Color(int.parse(hex, radix: 16));
hex == null ? null : Color(int.parse(hex, radix: 16));
Brightness getBrightness(Color color) => Brightness getBrightness(Color color) => ThemeData.estimateBrightnessForColor(color);
ThemeData.estimateBrightnessForColor(color);
List<Color> generateColorList() { List<Color> generateColorList() {
List<Color> colors = []; List<Color> colors = [];
@@ -60,7 +56,7 @@ extension MonetaryExtension on double {
return "\$${pieces.first}.00"; return "\$${pieces.first}.00";
} else { } else {
if (pieces.length > 2) { if (pieces.length > 2) {
printBlue(pieces); printColor(pieces, textColor: TextColor.blue);
} }
return '\$${pieces[0]}.${pieces[1].padRight(2, "0")}'; return '\$${pieces[0]}.${pieces[1].padRight(2, "0")}';
} }
@@ -83,7 +79,7 @@ void showSnack(
Duration duration = const Duration(seconds: 2)}) { Duration duration = const Duration(seconds: 2)}) {
final messengerKey = ref.read(scaffoldMessengerKeyProvider); final messengerKey = ref.read(scaffoldMessengerKeyProvider);
if (messengerKey.currentState == null) { if (messengerKey.currentState == null) {
printPink('Cannot show snackbar, state == null'); printColor('Cannot show snackbar, state == null', textColor: TextColor.red);
return; return;
} }
final color = type == SnackType.info final color = type == SnackType.info
@@ -99,8 +95,7 @@ void showSnack(
elevation: 8, elevation: 8,
backgroundColor: Styles.deepPurpleNurple, backgroundColor: Styles.deepPurpleNurple,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
), ),
content: Padding( content: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@@ -108,9 +103,7 @@ void showSnack(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(right: 14.0), padding: const EdgeInsets.only(right: 14.0),
child: Icon( child: Icon(type == SnackType.success ? Icons.check_circle : Icons.info, color: color),
type == SnackType.success ? Icons.check_circle : Icons.info,
color: color),
), ),
Text(text, style: textStyle), Text(text, style: textStyle),
], ],
@@ -120,8 +113,7 @@ void showSnack(
} }
bool isEmailValid(String email) { bool isEmailValid(String email) {
final RegExp regex = final RegExp regex = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$");
RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$");
return regex.hasMatch(email); return regex.hasMatch(email);
} }
+10 -20
View File
@@ -1,7 +1,6 @@
import 'package:animated_splash_screen/animated_splash_screen.dart'; import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/misc_build/build_media.dart';
import 'package:rluv/features/account/account_create_screen.dart'; import 'package:rluv/features/account/account_create_screen.dart';
import 'package:rluv/features/budget/screens/budget_overview.dart'; import 'package:rluv/features/budget/screens/budget_overview.dart';
import 'package:rluv/features/notes/screens/notes_screen.dart'; import 'package:rluv/features/notes/screens/notes_screen.dart';
@@ -74,8 +73,7 @@ class _HomeState extends ConsumerState<Home> {
} }
WidgetsBinding.instance.addPostFrameCallback( WidgetsBinding.instance.addPostFrameCallback(
(_) { (_) {
ref.read(currentHomePageProvider.notifier).state = ref.read(currentHomePageProvider.notifier).state = const BudgetOverviewScreen(initialData: {});
const BudgetOverviewScreen(initialData: {});
}, },
); );
super.initState(); super.initState();
@@ -92,8 +90,7 @@ class _HomeState extends ConsumerState<Home> {
); );
}); });
} }
if (ref.watch(currentHomePageProvider).toString() == if (ref.watch(currentHomePageProvider).toString() == "BudgetOverviewScreen") {
"BudgetOverviewScreen") {
initData = {}; initData = {};
} }
return Scaffold( return Scaffold(
@@ -104,15 +101,13 @@ class _HomeState extends ConsumerState<Home> {
child: SafeArea( child: SafeArea(
child: Column( child: Column(
children: [ children: [
SizedBox(height: BuildMedia(context).height * 0.15), SizedBox(height: MediaQuery.of(context).size.height * 0.15),
UiButton( UiButton(
text: 'Budget', text: 'Budget',
color: drawerColors[4], color: drawerColors[4],
onPressed: () { onPressed: () {
if (ref.read(currentHomePageProvider).toString() != if (ref.read(currentHomePageProvider).toString() != "BudgetOverviewScreen") {
"BudgetOverviewScreen") { ref.read(currentHomePageProvider.notifier).state = BudgetOverviewScreen(initialData: initData);
ref.read(currentHomePageProvider.notifier).state =
BudgetOverviewScreen(initialData: initData);
} }
toggleDrawer(); toggleDrawer();
}, },
@@ -121,10 +116,8 @@ class _HomeState extends ConsumerState<Home> {
text: 'Notes', text: 'Notes',
color: drawerColors[5], color: drawerColors[5],
onPressed: () { onPressed: () {
if (ref.read(currentHomePageProvider).toString() != if (ref.read(currentHomePageProvider).toString() != "SharedNotesScreen") {
"SharedNotesScreen") { ref.read(currentHomePageProvider.notifier).state = SharedNotesScreen(initialData: initData);
ref.read(currentHomePageProvider.notifier).state =
SharedNotesScreen(initialData: initData);
} }
toggleDrawer(); toggleDrawer();
}, },
@@ -134,10 +127,8 @@ class _HomeState extends ConsumerState<Home> {
text: 'Settings', text: 'Settings',
color: drawerColors[0], color: drawerColors[0],
onPressed: () { onPressed: () {
if (ref.read(currentHomePageProvider).toString() != if (ref.read(currentHomePageProvider).toString() != "SettingsScreen") {
"SettingsScreen") { ref.read(currentHomePageProvider.notifier).state = const SettingsScreen();
ref.read(currentHomePageProvider.notifier).state =
const SettingsScreen();
} }
toggleDrawer(); toggleDrawer();
}, },
@@ -190,5 +181,4 @@ final appBarTitleProvider = Provider<String>(
); );
final scaffoldMessengerKeyProvider = final scaffoldMessengerKeyProvider =
Provider<GlobalKey<ScaffoldMessengerState>>( Provider<GlobalKey<ScaffoldMessengerState>>((ref) => GlobalKey<ScaffoldMessengerState>());
(ref) => GlobalKey<ScaffoldMessengerState>());
+27
View File
@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'budget.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Budget _$BudgetFromJson(Map<String, dynamic> json) => Budget(
id: json['id'] as int?,
familyId: json['family_id'] as int,
name: json['name'] as String,
expectedIncome: (json['expected_income'] as num?)?.toDouble(),
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$BudgetToJson(Budget instance) => <String, dynamic>{
'id': instance.id,
'family_id': instance.familyId,
'expected_income': instance.expectedIncome,
'name': instance.name,
'hide': boolToJson(instance.hide),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
+31
View File
@@ -0,0 +1,31 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'budget_category_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BudgetCategory _$BudgetCategoryFromJson(Map<String, dynamic> json) =>
BudgetCategory(
id: json['id'] as int?,
budgetId: json['budget_id'] as int,
name: json['name'] as String,
color: colorFromJson(json['color'] as String),
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
amount: (json['amount'] as num).toDouble(),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$BudgetCategoryToJson(BudgetCategory instance) =>
<String, dynamic>{
'budget_id': instance.budgetId,
'id': instance.id,
'name': instance.name,
'amount': instance.amount,
'hide': boolToJson(instance.hide),
'color': colorToJson(instance.color),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
+24
View File
@@ -0,0 +1,24 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'family_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
FamilyModel _$FamilyModelFromJson(Map<String, dynamic> json) => FamilyModel(
id: json['id'] as int,
code: json['code'] as String?,
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$FamilyModelToJson(FamilyModel instance) =>
<String, dynamic>{
'id': instance.id,
'code': instance.code,
'hide': boolToJson(instance.hide),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
+38
View File
@@ -0,0 +1,38 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'shared_note.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
SharedNote _$SharedNoteFromJson(Map<String, dynamic> json) => SharedNote(
id: json['id'] as int?,
familyId: json['family_id'] as int,
createdByUserId: json['created_by_user_id'] as int,
content: json['content'] as String,
title: json['title'] as String,
color: optionalColorFromJson(json['color'] as String?),
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
tagIds: _tagIdsFromJson(json['tag_ids'] as String),
isMarkdown: json['is_markdown'] == null
? false
: boolFromJson(json['is_markdown'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$SharedNoteToJson(SharedNote instance) =>
<String, dynamic>{
'id': instance.id,
'family_id': instance.familyId,
'created_by_user_id': instance.createdByUserId,
'content': instance.content,
'title': instance.title,
'tag_ids': _tagIdsToJson(instance.tagIds),
'color': optionalColorToJson(instance.color),
'is_markdown': boolToJson(instance.isMarkdown),
'hide': boolToJson(instance.hide),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
+33
View File
@@ -0,0 +1,33 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tag.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Tag _$TagFromJson(Map<String, dynamic> json) => Tag(
id: json['id'] as int?,
familyId: json['family_id'] as int,
createdByUserId: json['created_by_user_id'] as int,
name: json['name'] as String,
type: $enumDecode(_$TagTypeEnumMap, json['type']),
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$TagToJson(Tag instance) => <String, dynamic>{
'id': instance.id,
'family_id': instance.familyId,
'created_by_user_id': instance.createdByUserId,
'name': instance.name,
'type': _$TagTypeEnumMap[instance.type]!,
'hide': boolToJson(instance.hide),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
const _$TagTypeEnumMap = {
TagType.note: 'note',
};
+21
View File
@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'token.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Token _$TokenFromJson(Map<String, dynamic> json) => Token(
userId: json['user_id'] as int,
familyId: json['family_id'] as int,
generatedAt: dateFromJson(json['generated_at'] as int),
expiresAt: dateFromJson(json['expires_at'] as int),
);
Map<String, dynamic> _$TokenToJson(Token instance) => <String, dynamic>{
'family_id': instance.familyId,
'user_id': instance.userId,
'generated_at': dateToJson(instance.generatedAt),
'expires_at': dateToJson(instance.expiresAt),
};
+41
View File
@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'transaction_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction(
id: json['id'] as int?,
amount: (json['amount'] as num).toDouble(),
type: $enumDecode(_$TransactionTypeEnumMap, json['type']),
budgetId: json['budget_id'] as int,
budgetCategoryId: json['budget_category_id'] as int?,
createdByUserId: json['created_by_user_id'] as int,
date: dateFromJson(json['date'] as int),
memo: json['memo'] as String?,
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$TransactionToJson(Transaction instance) =>
<String, dynamic>{
'id': instance.id,
'budget_category_id': instance.budgetCategoryId,
'budget_id': instance.budgetId,
'created_by_user_id': instance.createdByUserId,
'amount': instance.amount,
'memo': instance.memo,
'type': _$TransactionTypeEnumMap[instance.type]!,
'hide': boolToJson(instance.hide),
'date': dateToJson(instance.date),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
};
const _$TransactionTypeEnumMap = {
TransactionType.income: 'income',
TransactionType.expense: 'expense',
};
+33
View File
@@ -0,0 +1,33 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) => User(
id: json['id'] as int?,
name: json['name'] as String,
familyId: json['family_id'] as int,
budgetId: json['budget_id'] as int,
email: json['email'] as String?,
username: json['username'] as String?,
createdAt: dateFromJson(json['created_at'] as int),
updatedAt: dateFromJson(json['updated_at'] as int),
lastActivityAt: dateFromJson(json['last_activity_at'] as int),
hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
);
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'id': instance.id,
'family_id': instance.familyId,
'budget_id': instance.budgetId,
'name': instance.name,
'username': instance.username,
'email': instance.email,
'hide': boolToJson(instance.hide),
'created_at': dateToJson(instance.createdAt),
'updated_at': dateToJson(instance.updatedAt),
'last_activity_at': dateToJson(instance.lastActivityAt),
};
+1 -1
View File
@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "rluv") set(BINARY_NAME "rluv")
# The unique GTK application identifier for this application. See: # The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID # https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.rluv") set(APPLICATION_ID "com.fosscat.rluv")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake. # versions of CMake.
+20
View File
@@ -0,0 +1,20 @@
package_rename_config:
android:
app_name: rluv
package_name: com.fosscat.rluv
override_old_package: com.example.rluv
lang: kotlin
ios:
app_name: rluv
bundle_name: fosscatrluv
package_name: com.fosscat.rluv
web:
app_name: rluv
description: Package to change project configurations.
linux:
app_name: rluv
package_name: com.fosscat.rluv
exe_name: rluv
+12
View File
@@ -0,0 +1,12 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=rluv
Comment=Budget App
Categories=Utility;
Icon=com.fosscat.rluv
Exec=rluv
Terminal=false
StartupWMClass=rluv
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generator for metainfo & .desktop files:
https://www.freedesktop.org/software/appstream/metainfocreator/#/
-->
<component type="desktop-application">
<id>com.fosscat.rluv</id>
<name>rluv</name>
<summary>A budget app made with love</summary>
<developer_name>Nate Anderson</developer_name>
<url type="homepage">https://git.fosscat.com/n8r/rluv_client</url>
<metadata_license></metadata_license>
<project_license></project_license>
<supports>
<control>pointing</control>
<control>keyboard</control>
<control>touch</control>
</supports>
<description>
<p>A budgeting app for my needs. Maybe your too?</p>
</description>
<launchable type="desktop-id">com.fosscat.rluv.desktop</launchable>
<screenshots>
<!-- <screenshot type="default"> -->
<!-- <image>https://raw.githubusercontent.com/Merrit/flutter_flatpak_example/main/screenshots/screenshot.png</image> -->
<!-- </screenshot> -->
</screenshots>
<content_rating type="oars-1.1" />
<releases>
<release version="0.0.1" date="2024-06-02" />
</releases>
</component>
+87 -39
View File
@@ -157,10 +157,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.2" version: "1.18.0"
colorful_print:
dependency: "direct main"
description:
name: colorful_print
sha256: "2c9784a0d5e6dcd480a0d4ab67b7263e19d31644a30a8bc7f67ceb6db89549c7"
url: "https://pub.dev"
source: hosted
version: "0.1.2"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@@ -177,14 +185,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.3"
cupertino_icons: csslib:
dependency: "direct main" dependency: transitive
description: description:
name: cupertino_icons name: csslib
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "1.0.0"
custom_refresh_indicator: custom_refresh_indicator:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -304,14 +312,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.1"
helpers:
dependency: "direct main"
description:
name: helpers
sha256: d82a48e5acd45e3650af20779cf61326dd9c1aaf729fdab4ae721dc48f28b840
url: "https://pub.dev"
source: hosted
version: "1.2.3"
highlight: highlight:
dependency: transitive dependency: transitive
description: description:
@@ -320,6 +320,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" version: "0.7.0"
html:
dependency: transitive
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev"
source: hosted
version: "0.15.4"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@@ -400,6 +408,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@@ -408,6 +440,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
logger:
dependency: transitive
description:
name: logger
sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4
url: "https://pub.dev"
source: hosted
version: "2.3.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@@ -436,26 +476,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16" version: "0.12.16+1"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.8.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.12.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -472,6 +512,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
package_rename:
dependency: "direct dev"
description:
name: package_rename
sha256: "5066d021830f7a984f66a3d6912b0b95efb1d91f14322ba26ceacce2a62fd312"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
page_transition: page_transition:
dependency: transitive dependency: transitive
description: description:
@@ -484,10 +532,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.3" version: "1.9.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -689,10 +737,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.11.1"
state_notifier: state_notifier:
dependency: transitive dependency: transitive
description: description:
@@ -705,10 +753,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
stream_transform: stream_transform:
dependency: transitive dependency: transitive
description: description:
@@ -737,10 +785,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.0" version: "0.7.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@@ -853,6 +901,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.0+2" version: "0.4.0+2"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "14.2.1"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@@ -861,14 +917,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@@ -910,5 +958,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.1.0-185.0.dev <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.10.0" flutter: ">=3.18.0-18.0.pre.54"
+4 -63
View File
@@ -1,44 +1,18 @@
name: rluv name: rluv
description: A new Flutter project. description: A budget app for lovers
# The following line prevents the package from being accidentally published to publish_to: 'none'
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: '>=2.19.6 <3.0.0' sdk: '>=2.19.6 <3.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dio: ^5.2.1+1 dio: ^5.2.1+1
flutter_riverpod: ^2.1.3 flutter_riverpod: ^2.1.3
helpers: ^1.2.0
uuid: ^3.0.7 uuid: ^3.0.7
colorful_print: ^0.1.2
json_annotation: ^4.8.0 json_annotation: ^4.8.0
shared_preferences: ^2.1.2 shared_preferences: ^2.1.2
intl: ^0.18.1 intl: ^0.18.1
@@ -50,52 +24,19 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
build_runner: ^2.3.3 build_runner: ^2.3.3
json_serializable: ^6.6.0 json_serializable: ^6.6.0
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
icons_launcher: ^2.1.3 icons_launcher: ^2.1.3
package_rename: ^1.6.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter: flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets: assets:
- assets/ - assets/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
icons_launcher: icons_launcher:
image_path: "assets/app_icon.png" image_path: "assets/app_icon.png"
platforms: platforms:
+8 -8
View File
@@ -1,6 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html><html><head>
<html>
<head>
<!-- <!--
If you are serving your web app in a path other than the root, change the If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from. href value below to reflect the base path you are serving from.
@@ -18,7 +16,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project."> <meta name="description" content="Package to change project configurations.">
<!-- iOS meta tags & icons --> <!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
@@ -27,7 +25,7 @@
<link rel="apple-touch-icon" href="icons/Icon-192.png"> <link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/> <link rel="icon" type="image/png" href="favicon.png">
<title>rluv</title> <title>rluv</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
@@ -37,7 +35,7 @@
var serviceWorkerVersion = null; var serviceWorkerVersion = null;
</script> </script>
<!-- This script adds the flutter initialization JS code --> <!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script> <script src="flutter.js" defer=""></script>
</head> </head>
<body> <body>
<script> <script>
@@ -55,5 +53,7 @@
}); });
}); });
</script> </script>
</body>
</html>
</body></html>
+1 -1
View File
@@ -5,7 +5,7 @@
"display": "standalone", "display": "standalone",
"background_color": "#0175C2", "background_color": "#0175C2",
"theme_color": "#0175C2", "theme_color": "#0175C2",
"description": "A new Flutter project.", "description": "Package to change project configurations.",
"orientation": "portrait-primary", "orientation": "portrait-primary",
"prefer_related_applications": false, "prefer_related_applications": false,
"icons": [ "icons": [