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
3 changes: 3 additions & 0 deletions .fvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"flutter": "3.27.1"
}
56 changes: 56 additions & 0 deletions .github/workflows/build_web.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Build & Deploy Web

on:
workflow_dispatch:
push:
branches:
- main

# Required for GitHub Pages deployment
permissions:
contents: read
pages: write
id-token: write

# Only allow one concurrent deployment
concurrency:
group: pages
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.27.1'

- name: Install dependencies
run: flutter pub get

- name: Add web platform support
run: flutter create --platforms=web .

- name: Build web
run: |
flutter build web --release \
--base-href "/${{ github.event.repository.name }}/"

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: build/web

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,7 @@ app.*.symbols
!/dev/ci/**/Gemfile.lock
!.vscode/settings.json
*.noindex**
Logs/
Logs/

# FVM Version Cache
.fvm/
30 changes: 30 additions & 0 deletions .metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "17025dd88227cd9532c33fa78f5250d548d87e9a"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: web
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.27.1"
}
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The app is compatible with both Android and iOS.
| - | - |
| **Build APK** | ![CI](https://github.com/andreped/IronFlow/workflows/Build%20APK/badge.svg) |
| **Build IPA** | ![CI](https://github.com/andreped/IronFlow/workflows/Build%20IPA/badge.svg) |
| **Build Web** | ![CI](https://github.com/andreped/IronFlow/workflows/Build%20%26%20Deploy%20Web/badge.svg) |
| **Create Release** | ![CI](https://github.com/andreped/IronFlow/workflows/Create%20Release/badge.svg) |
| **Integration tests** | ![CI](https://github.com/andreped/IronFlow/workflows/Integration%20Tests/badge.svg) |
| **Linting** | ![CI](https://github.com/andreped/IronFlow/workflows/Linting/badge.svg) |
Expand All @@ -57,6 +58,53 @@ To run integration tests, run the command:
maestro test .maestro/integration_tests.yml
```

## [Development](https://github.com/andreped/IronFlow#Development)

This project uses [fvm](https://fvm.app) to pin the Flutter version. Install it first:

```bash
brew tap leoafarias/fvm
brew install fvm
```

Then install the pinned Flutter version and fetch dependencies:

```bash
fvm install
fvm flutter pub get
```

### Run

```bash
# Mobile (Android/iOS emulator or device)
fvm flutter run

# Web (opens Chrome)
fvm flutter run -d chrome
```

### Build

```bash
# Android
fvm flutter build apk --release

# Web
fvm flutter build web --release
```

The web build output is in `build/web/`. Serve it locally with:

```bash
npx serve build/web
```

### Deploy web to GitHub Pages

Push to `main` or trigger the **Build & Deploy Web** workflow manually from the Actions tab.
The app will be live at `https://<your-username>.github.io/IronFlow/`.

## [Getting Started](https://github.com/andreped/IronFlow#Getting-Started)

A cross-platform mobile app was developed to test the produced solutions. Installers for both
Expand Down
11 changes: 11 additions & 0 deletions lib/core/database.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:file_picker/file_picker.dart';
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import '../common/constants.dart';
Expand Down Expand Up @@ -572,6 +573,11 @@ class DatabaseHelper {
}

Future<void> backupDatabase(BuildContext context) async {
if (kIsWeb) {
await _showDialog(
context, 'Not Supported', 'Database backup is not available on web.');
return;
}
try {
// set backupPath for each OS, android and iOS
String backupPath;
Expand All @@ -597,6 +603,11 @@ class DatabaseHelper {
}

Future<void> restoreDatabase(BuildContext context) async {
if (kIsWeb) {
await _showDialog(context, 'Not Supported',
'Database restore is not available on web.');
return;
}
try {
String filePath;
if (Platform.isIOS) {
Expand Down
2 changes: 2 additions & 0 deletions lib/core/database_init.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'database_init_stub.dart'
if (dart.library.html) 'database_init_web.dart';
3 changes: 3 additions & 0 deletions lib/core/database_init_stub.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Future<void> initializeDatabaseFactory() async {
// No-op on native platforms — sqflite uses its built-in factory.
}
6 changes: 6 additions & 0 deletions lib/core/database_init_web.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:sqflite/sqflite.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';

Future<void> initializeDatabaseFactory() async {
databaseFactory = databaseFactoryFfiWeb;
}
5 changes: 4 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'components/scroll/custom_scroll_behavior.dart';
import 'tabs/home_tab.dart';
import 'core/theme/app_themes.dart';
import 'core/database_init.dart';

void main() {
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeDatabaseFactory();
runApp(const MyApp());
}

Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies:

# storage
sqflite: ^2.0.0+4
sqflite_common_ffi_web: ^0.4.3
path: ^1.8.0
path_provider: ^2.1.5
file_picker: ^8.1.7
Expand Down
30 changes: 30 additions & 0 deletions test/widget_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:ironflow/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());

// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();

// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
2 changes: 2 additions & 0 deletions web/_headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/*
X-Frame-Options: ALLOWALL
Binary file added web/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/icons/Icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/icons/Icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/icons/Icon-maskable-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/icons/Icon-maskable-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.

The path provided below has to start and end with a slash "/" in order for
it to work correctly.

For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">

<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">

<!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="ironflow">
<link rel="apple-touch-icon" href="icons/Icon-192.png">

<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>

<title>ironflow</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>
35 changes: 35 additions & 0 deletions web/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "ironflow",
"short_name": "ironflow",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
Loading