Skip to content

Commit be9af67

Browse files
committed
Implement basic app template
1 parent d0c674f commit be9af67

27 files changed

+2239
-772
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ Vulpine helps you to visualize and interact with command line tools. It is a sim
3434

3535
* Create app configuration files inside the app
3636
* You can also edit them with your favorite text editor
37-
* Create complex actions using a visual scripting editor
37+
* Create complex actions using a domain specific language (DSL)
38+
* The DSL is a simple and easy to use language that allows you to create complex actions with ease
39+
* The DSL is designed to be easy to read and write, even for non-programmers
3840
* Run apps with a single click
3941
* Add input fields to apps
4042
* Share apps with others

api/lib/models/parser.dart

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,20 +216,14 @@ class DslGrammarDefinition extends GrammarDefinition<VulpineDSL> {
216216
).map3((l, name, r) => VulpineDSLVariableStringPart(name));
217217

218218
Parser<EqualityOperator> equalityOperator() =>
219-
[
220-
string('==').map((_) => EqualityOperator.equal),
221-
string('!=').map((_) => EqualityOperator.notEqual),
222-
string('>').map((_) => EqualityOperator.greaterThan),
223-
string('<').map((_) => EqualityOperator.lessThan),
224-
string('>=').map((_) => EqualityOperator.greaterThanOrEqual),
225-
string('<=').map((_) => EqualityOperator.lessThanOrEqual),
226-
].toChoiceParser();
219+
EqualityOperator.values
220+
.map((e) => string(e.symbol).map((_) => e))
221+
.toChoiceParser();
227222

228223
Parser<LogicalOperator> logicalOperator() =>
229-
[
230-
string('&&').map((_) => LogicalOperator.and),
231-
string('||').map((_) => LogicalOperator.or),
232-
].toChoiceParser();
224+
LogicalOperator.values
225+
.map((e) => string(e.symbol).map((_) => e))
226+
.toChoiceParser();
233227

234228
Parser<VulpineDSLCondition> condition() => seq3(
235229
char('('),

app/AppImageBuilder.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
2+
version: 1
3+
script:
4+
- rm -rf AppDir || true
5+
- cp -r build/linux/x64/release/bundle AppDir
6+
- mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/
7+
- mkdir -p AppDir/usr/share/metainfo/
8+
- cp linux/debian/usr/share/icons/hicolor AppDir/usr/share/icons/hicolor -r
9+
- cp linux/debian/usr/share/metainfo/dev.linwood.vulpine.appdata.xml AppDir/usr/share/metainfo/
10+
11+
AppDir:
12+
path: ./AppDir
13+
app_info:
14+
id: dev.linwood.vulpine
15+
name: Linwood Vulpine
16+
icon: dev.linwood.vulpine
17+
version: 0.1.0
18+
exec: vulpine
19+
exec_args: $@
20+
apt:
21+
arch: amd64
22+
allow_unauthenticated: true
23+
sources:
24+
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse
25+
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe multiverse
26+
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse
27+
- sourceline: deb http://security.ubuntu.com/ubuntu bionic-security main restricted universe multiverse
28+
include:
29+
- libgtk-3-0
30+
- libsecret-1-dev
31+
- libjsoncpp-dev
32+
exclude:
33+
- humanity-icon-theme
34+
- hicolor-icon-theme
35+
- adwaita-icon-theme
36+
- ubuntu-mono
37+
files:
38+
include: []
39+
exclude:
40+
- usr/share/man
41+
- usr/share/doc/*/README.*
42+
- usr/share/doc/*/changelog.*
43+
- usr/share/doc/*/NEWS.*
44+
- usr/share/doc/*/TODO.*
45+
test:
46+
fedora-30:
47+
image: appimagecrafters/tests-env:fedora-30
48+
command: ./AppRun
49+
use_host_x: true
50+
debian-stable:
51+
image: appimagecrafters/tests-env:debian-stable
52+
command: ./AppRun
53+
use_host_x: true
54+
archlinux-latest:
55+
image: appimagecrafters/tests-env:archlinux-latest
56+
command: ./AppRun
57+
use_host_x: true
58+
centos-7:
59+
image: appimagecrafters/tests-env:centos-7
60+
command: ./AppRun
61+
use_host_x: true
62+
ubuntu-xenial:
63+
image: appimagecrafters/tests-env:ubuntu-xenial
64+
command: ./AppRun
65+
use_host_x: true
66+
runtime:
67+
env:
68+
GDK_BACKEND: x11
69+
GIO_MODULE_DIR: $APPDIR/usr/lib/x86_64-linux-gnu/gio/modules/
70+
AppImage:
71+
arch: x86_64
72+
update-information: guess

app/ButterflySetup.iss

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; Script generated by the Inno Setup Script Wizard.
2+
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3+
4+
#define MyAppName "Vulpine"
5+
#ifndef MyAppVersion
6+
#define MyAppVersion "1.0"
7+
#endif
8+
#define MyAppPublisher "Linwood"
9+
#define MyAppURL "https://www.linwood.dev"
10+
#define MyAppExeName "vulpine.exe"
11+
#define BaseDirRelease "build\windows\x64\runner\Release"
12+
#define RunnerSourceDir "windows\runner"
13+
14+
15+
[Setup]
16+
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
17+
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
18+
AppId={{966CE504-4AA5-49C7-A63B-74BD6C073E5B}
19+
AppName={#MyAppName}
20+
AppVersion={#MyAppVersion}
21+
AppVerName={#MyAppName} {#MyAppVersion}
22+
AppPublisher={#MyAppPublisher}
23+
AppPublisherURL={#MyAppURL}
24+
AppSupportURL={#MyAppURL}
25+
AppUpdatesURL={#MyAppURL}
26+
DefaultDirName={autopf64}\{#MyAppPublisher}\{#MyAppName}
27+
DefaultGroupName={#MyAppPublisher}\{#MyAppName}
28+
DisableProgramGroupPage=yes
29+
LicenseFile=..\LICENSE
30+
; Uncomment the following line to run in non administrative install mode (install for current user only.)
31+
PrivilegesRequired=lowest
32+
PrivilegesRequiredOverridesAllowed=dialog
33+
OutputDir=build\windows\x64
34+
OutputBaseFilename=linwood-vulpine-windows-setup
35+
SetupIconFile={#RunnerSourceDir}\resources\app_icon.ico
36+
UninstallDisplayIcon={app}\{#MyAppExeName}
37+
Compression=lzma
38+
SolidCompression=yes
39+
WizardStyle=modern
40+
Uninstallable=not WizardIsTaskSelected('portablemode')
41+
ChangesAssociations=yes
42+
43+
[Languages]
44+
Name: "english"; MessagesFile: "compiler:Default.isl"
45+
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
46+
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
47+
48+
[Tasks]
49+
Name: "desktopicon"; Description: "Create a Desktop shortcut"
50+
Name: "startmenu"; Description: "Create a Start Menu entry"
51+
52+
53+
[Files]
54+
Source: "{#BaseDirRelease}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
55+
Source: "{#BaseDirRelease}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
56+
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
57+
58+
59+
60+
[Registry]
61+
62+
[Icons]
63+
Name: "{group}\Visit Website"; Filename: "https://www.linwood.dev/"
64+
Name: "{group}\Vulpine Documentation"; Filename: "https://vulpine.linwood.dev/"
65+
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
66+
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
67+
68+
[Run]
69+
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

app/DmgSetup.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"title": "Linwood Vulpine",
3+
"icon": "build/macos/Build/Products/Release/vulpine.app/Contents/Resources/AppIcon.icns",
4+
"background-color": "#1b1b1d",
5+
"contents": [
6+
{ "x": 448, "y": 344, "type": "link", "path": "/Applications" },
7+
{ "x": 192, "y": 344, "type": "file", "path": "build/macos/Build/Products/Release/vulpine.app" }
8+
]
9+
}

app/android/app/build.gradle.kts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,39 @@ android {
2929
versionCode = flutter.versionCode
3030
versionName = flutter.versionName
3131
}
32-
32+
productFlavors {
33+
production {
34+
dimension "default"
35+
applicationIdSuffix ""
36+
manifestPlaceholders = [appName: "Vulpine"]
37+
}
38+
development {
39+
dimension "default"
40+
applicationIdSuffix ""
41+
manifestPlaceholders = [appName: "Vulpine Nightly"]
42+
}
43+
nightly {
44+
dimension "default"
45+
applicationIdSuffix ".nightly"
46+
manifestPlaceholders = [appName: "Vulpine Nightly"]
47+
}
48+
}
49+
signingConfigs {
50+
release {
51+
keyAlias keystoreProperties['keyAlias']
52+
keyPassword keystoreProperties['keyPassword']
53+
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
54+
storePassword keystoreProperties['storePassword']
55+
}
56+
}
3357
buildTypes {
3458
release {
35-
// TODO: Add your own signing config for the release build.
3659
// Signing with the debug keys for now, so `flutter run --release` works.
37-
signingConfig = signingConfigs.getByName("debug")
60+
if (keystorePropertiesFile.exists()) {
61+
signingConfig signingConfigs.release
62+
} else {
63+
signingConfig signingConfigs.debug
64+
}
3865
}
3966
}
4067
}

app/lib/cubits/settings.dart

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import 'package:dart_mappable/dart_mappable.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_bloc/flutter_bloc.dart';
4+
import 'package:material_leap/material_leap.dart';
5+
import 'package:shared_preferences/shared_preferences.dart';
6+
7+
part 'settings.mapper.dart';
8+
9+
@MappableEnum()
10+
enum ThemeDensity {
11+
system,
12+
maximize,
13+
desktop,
14+
compact,
15+
comfortable,
16+
standard;
17+
18+
VisualDensity toFlutter() => switch (this) {
19+
ThemeDensity.maximize => const VisualDensity(horizontal: -4, vertical: -4),
20+
ThemeDensity.desktop => const VisualDensity(horizontal: -3, vertical: -3),
21+
ThemeDensity.compact => VisualDensity.compact,
22+
ThemeDensity.comfortable => VisualDensity.comfortable,
23+
ThemeDensity.standard => VisualDensity.standard,
24+
ThemeDensity.system => VisualDensity.adaptivePlatformDensity,
25+
};
26+
}
27+
28+
final class ThemeModeMapper extends SimpleMapper<ThemeMode> {
29+
const ThemeModeMapper();
30+
31+
@override
32+
ThemeMode decode(Object value) {
33+
return ThemeMode.values.byName(value.toString());
34+
}
35+
36+
@override
37+
String encode(ThemeMode value) {
38+
return value.name;
39+
}
40+
}
41+
42+
@MappableClass(includeCustomMappers: [ThemeModeMapper()])
43+
class VulpineSettings with VulpineSettingsMappable, LeapSettings {
44+
final String locale;
45+
final ThemeMode themeMode;
46+
@override
47+
final bool nativeTitleBar;
48+
final String design;
49+
final ThemeDensity density;
50+
final bool highContrast;
51+
52+
const VulpineSettings({
53+
this.locale = '',
54+
this.themeMode = ThemeMode.system,
55+
this.nativeTitleBar = false,
56+
this.design = '',
57+
this.density = ThemeDensity.system,
58+
this.highContrast = false,
59+
});
60+
61+
factory VulpineSettings.fromPrefs(SharedPreferences prefs) => VulpineSettings(
62+
themeMode: ThemeMode.values.byName(
63+
prefs.getString('themeMode') ?? 'system',
64+
),
65+
design: prefs.getString('design') ?? '',
66+
nativeTitleBar: prefs.getBool('nativeTitleBar') ?? false,
67+
locale: prefs.getString('locale') ?? '',
68+
density: ThemeDensity.values.byName(prefs.getString('density') ?? 'system'),
69+
highContrast: prefs.getBool('highContrast') ?? false,
70+
);
71+
72+
Future<void> save() async {
73+
final prefs = await SharedPreferences.getInstance();
74+
await prefs.setString('themeMode', themeMode.name);
75+
await prefs.setString('design', design);
76+
await prefs.setBool('nativeTitleBar', nativeTitleBar);
77+
await prefs.setString('locale', locale);
78+
await prefs.setString('density', density.name);
79+
await prefs.setBool('highContrast', highContrast);
80+
}
81+
}
82+
83+
class SettingsCubit extends Cubit<VulpineSettings>
84+
with LeapSettingsBlocBaseMixin<VulpineSettings> {
85+
SettingsCubit(SharedPreferences prefs)
86+
: super(VulpineSettings.fromPrefs(prefs));
87+
88+
Future<void> changeThemeMode(ThemeMode mode) {
89+
emit(state.copyWith(themeMode: mode));
90+
return state.save();
91+
}
92+
93+
Future<void> changeDesign(String design) {
94+
emit(state.copyWith(design: design));
95+
return state.save();
96+
}
97+
98+
Future<void> changeNativeTitleBar(bool nativeTitleBar) {
99+
emit(state.copyWith(nativeTitleBar: nativeTitleBar));
100+
return state.save();
101+
}
102+
103+
Future<void> changeLocale(String locale) {
104+
emit(state.copyWith(locale: locale));
105+
return state.save();
106+
}
107+
108+
Future<void> changeDensity(ThemeDensity density) {
109+
emit(state.copyWith(density: density));
110+
return state.save();
111+
}
112+
113+
Future<void> changeHighContrast(bool highContrast) {
114+
emit(state.copyWith(highContrast: highContrast));
115+
return state.save();
116+
}
117+
118+
Future<void> importSettings(String data) {
119+
final settings = VulpineSettingsMapper.fromJson(data).copyWith();
120+
emit(settings);
121+
return state.save();
122+
}
123+
124+
Future<String> exportSettings() async {
125+
return state.toJson();
126+
}
127+
}

0 commit comments

Comments
 (0)