Add app source and tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
alvocool
2026-10-11 10:15:30 +03:00
parent 7e246255c2
commit 38881d1fe1
135 changed files with 21057 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
/// The callbacks [View{{screen}}] uses to hand results back to the screen, so
/// the ViewModel never touches widgets.
abstract class Connect{{screen}} {
// void onSomethingLoaded(SomeModel data);
}

View File

@@ -0,0 +1,24 @@
import '../parent/ParentViewModel.dart';
import 'Connect{{screen}}.dart';
class View{{screen}} extends ParentViewModel {
Connect{{screen}} connection;
View{{screen}}(super.context, this.connection);
// Every server-bound call follows this shape: guard with canReach, show the
// loading overlay, hand the result back through `connection`, and route any
// failure to handleError.
//
// void loadSomething(ServerProfile server) async {
// if (!await canReach(server, () => loadSomething(server))) return;
// showLoading('Loading…');
// try {
// final result = await getDataManager().someCall(server);
// closeLoading();
// connection.onSomethingLoaded(result);
// } catch (error) {
// handleError(error, () => loadSomething(server), () {}, 'Retry');
// }
// }
}

View File

@@ -0,0 +1,10 @@
import 'package:flutter/cupertino.dart';
import '{{screen}}State.dart';
class {{screen}} extends StatefulWidget {
const {{screen}}({super.key});
@override
State<{{screen}}> createState() => {{screen}}State();
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../designs/Responsive.dart';
import 'Connect{{screen}}.dart';
import 'View{{screen}}.dart';
import '{{screen}}.dart';
class {{screen}}State extends State<{{screen}}> implements Connect{{screen}} {
View{{screen}}? _model;
@override
Widget build(BuildContext context) {
return ViewModelBuilder<View{{screen}}>.reactive(
viewModelBuilder: () => View{{screen}}(context, this),
onViewModelReady: _onReady,
builder: (context, viewModel, child) => Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Responsive(
mobile: _mobileView(constraints),
tablet: _tabletView(constraints),
desktop: _desktopView(constraints),
),
),
),
);
}
void _onReady(View{{screen}} model) {
_model = model;
// onViewModelReady fires mid-build; a synchronous setState from the
// first load would dirty this State while it is still being built.
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _initiate();
});
}
/// The single entry point for whatever this screen loads on open. Kick off
/// every initial load from here — never inline in `onViewModelReady`.
Future<void> _initiate() async {
assert(_model != null, 'View{{screen}} should be ready before _initiate');
// _model?.loadSomething();
}
// ── named handlers ─────────────────────────────────────────────────────────
// ── Connect{{screen}} ──────────────────────────────────────────────────────
// ── layouts ────────────────────────────────────────────────────────────────
Widget _mobileView(BoxConstraints constraints) {
return const SizedBox();
}
Widget _tabletView(BoxConstraints constraints) {
return const SizedBox();
}
Widget _desktopView(BoxConstraints constraints) {
return const SizedBox();
}
}

View File

@@ -0,0 +1,21 @@
name: mvvc_template
description: Generates a Peach screen as the mandatory four files — the
StatefulWidget shell, its State (UI + Connect implementation), the ViewModel
(logic, talks to the DataManager) and the Connect interface between them.
version: 0.1.0+1
environment:
mason: ^0.1.1
vars:
project:
type: string
description: The top-level folder under lib/ (also the package name)
default: Peach
prompt: What is your project name?
screen:
type: string
description: The screen name in PascalCase, e.g. ServerDetail
default: NewScreen
prompt: What is your screen name?