Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .env.stencil
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@ WALLETCONNECT_PROJECT_ID=<WALLETCONNECT_PROJECT_ID>
API_KEY=<PINATA_API_KEY>
API_SECRET=<PINATA_API_SECRET>
ALCHEMY_API_KEY=<ALCHEMY_API_KEY>
CONTRACT_ADDRESS=<CONTRACT_ADDRESS>
CONTRACT_ADDRESS=<CONTRACT_ADDRESS>
APPLICATION_ID=<APPLICATION_ID>


//CONTRACT ADDRESSES


TREE_NFT_CONTRACT_ADDRESS=<TREE_NFT_CONTRACT_ADDRESS>
ORGANISATION_FACTORY_CONTRACT_ADDRESS=<ORGANISATION_FACTORY_CONTRACT_ADDRESS>
CARE_TOKEN_CONTRACT_ADDRESS=<CARE_TOKEN_CONTRACT_ADDRESS>
VERIFIER_TOKEN_CONTRACT_ADDRESS=<VERIFIER_TOKEN_CONTRACT_ADDRESS>
LEGACY_TOKEN_CONTRACT_ADDRESS=<LEGACY_TOKEN_CONTRACT_ADDRESS>
PLANTER_TOKEN_CONTRACT_ADDRESS=<PLANTER_TOKEN_CONTRACT_ADDRESS>
35 changes: 35 additions & 0 deletions .github/workflows/flutter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Flutter CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Modernize action version and fix minor YAML lint issues.

  • Use actions/checkout@v4.
  • Trim trailing spaces (lines 17, 18, 23).
  • Single space after run: (line 35).
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
-      - name: Setup environment file from template 
-        run: cp .env.stencil .env 
+      - name: Setup environment file from template
+        run: cp .env.stencil .env
-          channel: 'stable' 
+          channel: 'stable'
-        run:  flutter build apk --release --no-tree-shake-icons
+        run: flutter build apk --release --no-tree-shake-icons

Also applies to: 17-18, 23-23, 35-35

🧰 Tools
🪛 actionlint (1.7.7)

15-15: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In .github/workflows/flutter.yaml around lines 15, 17-18, 23 and 35 update the
actions/checkout usage to actions/checkout@v4, remove any trailing spaces on
lines 17, 18 and 23, and ensure there is exactly one space after the run: key on
line 35; keep YAML indentation and quoting unchanged while making these minimal
edits.


- name: Setup environment file from template
run: cp .env.stencil .env

- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'

- name: Install dependencies
run: flutter pub get

- name: Dart analyze
run: flutter analyze

- name: Check formatting
run: dart format --output=none --set-exit-if-changed .

- name: Flutter build (apk)
run: flutter build apk --release --no-tree-shake-icons | grep -v "deprecated"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Build failures may be masked by piping to grep.

flutter build ... | grep -v "deprecated" returns grep's exit code; without pipefail, a failing build can pass. Remove the pipe (or set set -o pipefail).

-      - name: Flutter build (apk)
-        run:  flutter build apk --release --no-tree-shake-icons | grep -v "deprecated"
+      - name: Flutter build (apk)
+        run: flutter build apk --release --no-tree-shake-icons
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: flutter build apk --release --no-tree-shake-icons | grep -v "deprecated"
- name: Flutter build (apk)
run: flutter build apk --release --no-tree-shake-icons
🧰 Tools
🪛 YAMLlint (1.37.1)

[warning] 35-35: too many spaces after colon

(colons)

🤖 Prompt for AI Agents
In .github/workflows/flutter.yaml around line 35, the build command pipes
flutter build to grep which can mask failures because pipe exit status isn't
checked; either remove the pipe entirely and let the action surface build
errors, or ensure the shell runs with pipefail (use bash and set -o pipefail
before the command) so the workflow fails when flutter build fails while still
filtering out deprecated lines.

25 changes: 12 additions & 13 deletions lib/components/universal_navbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
bottom: 0,
left: 0,
right: 0,
child: Container(
child: SizedBox(
height: 40,
child: _buildPlantIllustrations(),
),
Expand All @@ -54,7 +54,7 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Colors.white.withOpacity(0.3),
color: Colors.white,
width: 1,
),
),
Expand Down Expand Up @@ -151,14 +151,13 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
Widget _buildPlantIllustrations() {
return Container(
decoration: BoxDecoration(
color: const Color.fromARGB(255, 251, 251, 99)
.withOpacity(0.9), // Beige background
color: const Color.fromARGB(255, 251, 251, 99),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(40),
topRight: Radius.circular(40),
),
border: Border.all(
color: Colors.black.withOpacity(0.2),
color: Colors.black,
width: 1,
),
),
Expand All @@ -183,7 +182,7 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: treeImages.map((imagePath) {
return Container(
return SizedBox(
width: plantWidth,
height: plantWidth,
child: Image.asset(
Expand Down Expand Up @@ -241,15 +240,15 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
constraints: const BoxConstraints(maxWidth: 100, minHeight: 20),
// Limit max width
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.green.withOpacity(0.3),
color: Colors.green,
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
color: Colors.black,
blurRadius: 4,
offset: const Offset(0, 2),
),
Expand All @@ -267,7 +266,7 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
color: Colors.green[700],
),
const SizedBox(width: 4),
Container(
SizedBox(
width: 10,
child: Flexible(
child: Text(
Expand Down Expand Up @@ -366,15 +365,15 @@ class UniversalNavbar extends StatelessWidget implements PreferredSizeWidget {
return Container(
constraints: const BoxConstraints(maxWidth: 80), // Limit max width
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.green.withOpacity(0.3),
color: Colors.green,
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
color: Colors.black,
blurRadius: 4,
offset: const Offset(0, 2),
),
Expand Down
5 changes: 5 additions & 0 deletions lib/components/wallet_connect_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ class WalletConnectDialog extends StatelessWidget {
onPressed: () async {
try {
await walletProvider.openWallet(wallet, uri);
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
} catch (e) {
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.toString()),
Expand Down Expand Up @@ -75,7 +78,9 @@ class WalletConnectDialog extends StatelessWidget {
child: OutlinedButton.icon(
onPressed: () async {
await Clipboard.setData(ClipboardData(text: uri));
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('URI copied to clipboard!'),
Expand Down
96 changes: 96 additions & 0 deletions lib/models/tree_details.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:tree_planting_protocol/utils/logger.dart';

class Tree {
final int id;
final int latitude;
final int longitude;
final int planting;
final int death;
final String species;
final String imageUri;
final String qrIpfsHash;
final String metadata;
final List<String> photos;
final String geoHash;
final List<String> ancestors;
final int lastCareTimestamp;
final int careCount;
final List<String> verifiers;
final String owner;

Tree({
required this.id,
required this.latitude,
required this.longitude,
required this.planting,
required this.death,
required this.species,
required this.imageUri,
required this.qrIpfsHash,
required this.metadata,
required this.photos,
required this.geoHash,
required this.ancestors,
required this.lastCareTimestamp,
required this.careCount,
required this.verifiers,
required this.owner,
});

factory Tree.fromContractData(
List<dynamic> userData, List<dynamic> verifiers, String owner) {
logger.d("User data, Verifiers and Owner");
logger.d(userData);
logger.d(verifiers);
logger.d(owner);
try {
return Tree(
id: _toInt(userData[0]),
latitude: _toInt(userData[1]),
longitude: _toInt(userData[2]),
planting: _toInt(userData[3]),
death: _toInt(userData[4]),
species: userData[5]?.toString() ?? '',
imageUri: userData[6]?.toString() ?? '',
qrIpfsHash: userData[7]?.toString() ?? '',
metadata: userData[8]?.toString() ?? '',
photos: userData[9] is List
? List<String>.from(userData[9].map((p) => p.toString()))
: [],
geoHash: userData[10]?.toString() ?? '',
ancestors: userData[11] is List
? List<String>.from(userData[11].map((a) => a.toString()))
: [],
lastCareTimestamp: _toInt(userData[12]),
careCount: _toInt(userData[13]),
verifiers: List<String>.from(verifiers.map((a) => a.toString())),
owner: owner,
);
} catch (e) {
Comment on lines +46 to +69
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate contract payload shape before indexing.

Direct indexing assumes ≥14 items; add a length guard to avoid RangeError and return a safe fallback with logging.

     try {
+      if (userData.length < 14) {
+        logger.e('Tree.fromContractData: insufficient userData length=${userData.length}');
+        return Tree(
+          id: 0,
+          latitude: 0,
+          longitude: 0,
+          planting: 0,
+          death: 0,
+          species: 'Unknown',
+          imageUri: '',
+          qrIpfsHash: '',
+          metadata: '',
+          photos: const [],
+          geoHash: '',
+          ancestors: const [],
+          lastCareTimestamp: 0,
+          careCount: 0,
+          verifiers: const [],
+          owner: '',
+        );
+      }
       return Tree(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
return Tree(
id: _toInt(userData[0]),
latitude: _toInt(userData[1]),
longitude: _toInt(userData[2]),
planting: _toInt(userData[3]),
death: _toInt(userData[4]),
species: userData[5]?.toString() ?? '',
imageUri: userData[6]?.toString() ?? '',
qrIpfsHash: userData[7]?.toString() ?? '',
metadata: userData[8]?.toString() ?? '',
photos: userData[9] is List
? List<String>.from(userData[9].map((p) => p.toString()))
: [],
geoHash: userData[10]?.toString() ?? '',
ancestors: userData[11] is List
? List<String>.from(userData[11].map((a) => a.toString()))
: [],
lastCareTimestamp: _toInt(userData[12]),
careCount: _toInt(userData[13]),
verifiers: List<String>.from(verifiers.map((a) => a.toString())),
owner: owner,
);
} catch (e) {
try {
if (userData.length < 14) {
logger.e('Tree.fromContractData: insufficient userData length=${userData.length}');
return Tree(
id: 0,
latitude: 0,
longitude: 0,
planting: 0,
death: 0,
species: 'Unknown',
imageUri: '',
qrIpfsHash: '',
metadata: '',
photos: const [],
geoHash: '',
ancestors: const [],
lastCareTimestamp: 0,
careCount: 0,
verifiers: const [],
owner: '',
);
}
return Tree(
id: _toInt(userData[0]),
latitude: _toInt(userData[1]),
longitude: _toInt(userData[2]),
planting: _toInt(userData[3]),
death: _toInt(userData[4]),
species: userData[5]?.toString() ?? '',
imageUri: userData[6]?.toString() ?? '',
qrIpfsHash: userData[7]?.toString() ?? '',
metadata: userData[8]?.toString() ?? '',
photos: userData[9] is List
? List<String>.from(userData[9].map((p) => p.toString()))
: [],
geoHash: userData[10]?.toString() ?? '',
ancestors: userData[11] is List
? List<String>.from(userData[11].map((a) => a.toString()))
: [],
lastCareTimestamp: _toInt(userData[12]),
careCount: _toInt(userData[13]),
verifiers: List<String>.from(verifiers.map((a) => a.toString())),
owner: owner,
);
} catch (e) {

return Tree(
id: 0,
latitude: 0,
longitude: 0,
planting: 0,
death: 0,
species: 'Unknown',
imageUri: '',
qrIpfsHash: '',
metadata: '',
photos: [],
geoHash: '',
ancestors: [],
lastCareTimestamp: 0,
careCount: 0,
verifiers: [],
owner: '',
);
}
}

static int _toInt(dynamic value) {
if (value is BigInt) return value.toInt();
if (value is int) return value;
return int.tryParse(value.toString()) ?? 0;
}
}
10 changes: 5 additions & 5 deletions lib/models/wallet_chain_option.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

final String ALCHEMY_API_KEY = dotenv.env['ALCHEMY_API_KEY'] ?? '';
final String alchemyApiKey = dotenv.env['ALCHEMY_API_KEY'] ?? '';

class WalletOption {
final String name;
Expand Down Expand Up @@ -30,14 +30,14 @@ final List<WalletOption> walletOptionsList = [
];

final Map<String, String> rpcUrls = {
'11155111': 'https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY',
'1': 'https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY',
'11155111': 'https://eth-sepolia.g.alchemy.com/v2/$alchemyApiKey',
'1': 'https://eth-mainnet.g.alchemy.com/v2/$alchemyApiKey',
};

final Map<String, Map<String, dynamic>> chainInfoList = {
'1': {
'name': 'Ethereum Mainnet',
'rpcUrl': 'https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY',
'rpcUrl': 'https://eth-mainnet.g.alchemy.com/v2/$alchemyApiKey',
'nativeCurrency': {
'name': 'Ether',
'symbol': 'ETH',
Expand All @@ -47,7 +47,7 @@ final Map<String, Map<String, dynamic>> chainInfoList = {
},
'11155111': {
'name': 'Sepolia Testnet',
'rpcUrl': 'https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY',
'rpcUrl': 'https://eth-sepolia.g.alchemy.com/v2/$alchemyApiKey',
'nativeCurrency': {
'name': 'Sepolia Ether',
'symbol': 'SEP',
Expand Down
2 changes: 0 additions & 2 deletions lib/pages/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'package:provider/provider.dart';
import 'package:tree_planting_protocol/providers/wallet_provider.dart';

import 'package:tree_planting_protocol/utils/constants/navbar_constants.dart';
import 'package:tree_planting_protocol/utils/constants/route_constants.dart';

import 'package:tree_planting_protocol/widgets/basic_scaffold.dart';
import 'package:tree_planting_protocol/widgets/profile_widgets/profile_section_widget.dart';
Expand Down
3 changes: 2 additions & 1 deletion lib/pages/mint_nft/mint_nft_coordinates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:tree_planting_protocol/providers/mint_nft_provider.dart';
import 'package:tree_planting_protocol/utils/constants/route_constants.dart';
import 'package:tree_planting_protocol/widgets/basic_scaffold.dart';
import 'package:tree_planting_protocol/widgets/map_widgets/flutter_map_widget.dart';
import 'package:tree_planting_protocol/widgets/nft_display_utils/tree_NFT_view_widget.dart';
import 'package:tree_planting_protocol/widgets/nft_display_utils/tree_nft_view_widget.dart';
import 'package:tree_planting_protocol/utils/services/get_current_location.dart';
import 'package:dart_geohash/dart_geohash.dart';

Expand Down Expand Up @@ -618,6 +618,7 @@ class _MintNftCoordinatesPageState extends State<MintNftCoordinatesPage> {
);
}

// ignore: unused_element
Widget _buildPreviewSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
Expand Down
Loading