Skip to content
Open
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
26 changes: 0 additions & 26 deletions .github/workflows/deploy.yaml

This file was deleted.

11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ Ejemplo de app: [▶️ vídeo en YouTube](https://youtu.be/5UdYlEhAuTE)
Los diferentes pasos incluyen:

- 1, el resumen en una sola frase
- 2, ampliación del resulen con actos pricipales y final
- 2, ampliación del resumen con actos pricipales y final
- 3, describiendo al protagonista, con los diferentes elementos:

- 4, convitiendo cada frase del paso 2 y convertirlo en un nuevo párrafo
- motivaciones
- objetivos
- conflicto
- epifanía
- 4, recoge cada frase del paso 2 y convertirlo en un nuevo párrafo
- 5, describir a los personajes pricipales
- 6, volver al punto cuatro y ampliar argumento
- 7, crea tablas de personaje para los principales, siguiendo la estructura del punto tres
- 7, crea tablas de personaje para los principales, siguiendo la estructura del punto 3
- 8, usando el argumento ampliado, escribe una lista de las escenas que faltan para completar la historia
- 9, de cada escena en la lista, escribe un resumen narrativo (con varios párrafos)

Expand Down
2 changes: 1 addition & 1 deletion src/fireflake/.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ migration:
- platform: root
create_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
base_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
- platform: web
- platform: windows
create_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
base_revision: d7b523b356d15fb81e7d340bbe52b47f93937323

Expand Down
152 changes: 113 additions & 39 deletions src/fireflake/lib/author_info_page.dart
Original file line number Diff line number Diff line change
@@ -1,64 +1,138 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'state/author_cubit.dart';
import 'models/author_settings.dart';
import 'utils/responsive_helper.dart';

class AuthorInfoPage extends StatefulWidget {
const AuthorInfoPage({super.key});
const AuthorInfoPage({super.key});

@override
State<AuthorInfoPage> createState() => _AuthorInfoPageState();
}

class _AuthorInfoPageState extends State<AuthorInfoPage> {
final _formKey = GlobalKey<FormState>();
String _name = '';
String _bio = '';
String _email = '';
late TextEditingController _nameController;
late TextEditingController _bioController;
late TextEditingController _emailController;

@override
void initState() {
super.initState();
_nameController = TextEditingController();
_bioController = TextEditingController();
_emailController = TextEditingController();
}

@override
void dispose() {
_nameController.dispose();
_bioController.dispose();
_emailController.dispose();
super.dispose();
}

void _submit() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
context.read<AuthorCubit>().updateAll(
name: _nameController.text,
bio: _bioController.text,
email: _emailController.text,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Author info saved')),
const SnackBar(content: Text('Author info saved')),
);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Add Author Info')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: ListView(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
validator: (value) =>
value == null || value.isEmpty ? 'Enter name' : null,
onSaved: (value) => _name = value ?? '',
),
TextFormField(
decoration: InputDecoration(labelText: 'Bio'),
maxLines: 3,
onSaved: (value) => _bio = value ?? '',
),
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value) =>
value == null || value.isEmpty ? 'Enter email' : null,
onSaved: (value) => _email = value ?? '',
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _submit,
child: Text('Save'),
appBar: AppBar(title: const Text('Author Information')),
body: BlocBuilder<AuthorCubit, AuthorSettings>(
builder: (context, settings) {
if (_nameController.text != settings.name) {
_nameController.text = settings.name;
}
if (_bioController.text != settings.bio) {
_bioController.text = settings.bio;
}
if (_emailController.text != settings.email) {
_emailController.text = settings.email;
}

return ResponsiveWrapper(
child: Padding(
padding: ResponsiveHelper.getContentPadding(context),
child: Form(
key: _formKey,
child: ListView(
children: [
const Text(
'This configuration is stored globally and will be used across all projects.',
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey,
),
),
const SizedBox(height: 16),
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
validator: (value) => value == null || value.isEmpty
? 'Enter your name'
: null,
),
const SizedBox(height: 16),
TextFormField(
controller: _bioController,
decoration: const InputDecoration(
labelText: 'Bio',
border: OutlineInputBorder(),
alignLabelWithHint: true,
),
maxLines: 5,
),
const SizedBox(height: 16),
TextFormField(
controller: _emailController,
decoration: const InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Enter your email';
}
if (!value.contains('@')) {
return 'Enter a valid email';
}
return null;
},
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _submit,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
),
child: const Text(
'Save',
style: TextStyle(fontSize: 16),
),
),
],
),
),
],
),
),
),
);
},
),
);
}
}
}
72 changes: 72 additions & 0 deletions src/fireflake/lib/data/project_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

import '../models/project.dart';

class ProjectStorage {
static const String _folderName = 'projects';

static Future<Directory> _baseDir() async {
final dir = await getApplicationDocumentsDirectory();
final target = Directory(p.join(dir.path, 'fireflake', _folderName));
if (!await target.exists()) {
await target.create(recursive: true);
}
return target;
}

static String _fileName(String title) {
final slug = title
.toLowerCase()
.replaceAll(RegExp(r'[^a-z0-9]+'), '-')
.replaceAll(RegExp(r'-+'), '-')
.trim();
final safe = slug.isEmpty ? 'project' : slug;
return '$safe.json';
}

static Future<List<Project>> loadProjects() async {
final dir = await _baseDir();
final files =
dir.listSync().whereType<File>().where((f) => f.path.endsWith('.json'));
final projects = <Project>[];
for (final file in files) {
try {
final jsonStr = await file.readAsString();
final map = json.decode(jsonStr) as Map<String, dynamic>;
projects.add(Project.fromJson(map));
} catch (_) {
// ignore malformed files
}
}
return projects;
}

static Future<Project?> loadProjectByTitle(String title) async {
final dir = await _baseDir();
final file = File(p.join(dir.path, _fileName(title)));
if (!await file.exists()) return null;
final jsonStr = await file.readAsString();
final map = json.decode(jsonStr) as Map<String, dynamic>;
return Project.fromJson(map);
}

static Future<void> saveProject(Project project, [String? filename]) async {
final dir = await _baseDir();
final actualFilename = filename ?? _fileName(project.title);
final file = File(p.join(dir.path, actualFilename));
final jsonStr = json.encode(project.toJson());
await file.writeAsString(jsonStr);
}

static Future<void> deleteProject(String title) async {
final dir = await _baseDir();
final file = File(p.join(dir.path, _fileName(title)));
if (await file.exists()) {
await file.delete();
}
}
}
Loading