Skip to content

Commit

Permalink
refactor song editor
Browse files Browse the repository at this point in the history
  • Loading branch information
angelocordero committed Jun 4, 2023
1 parent da234e2 commit 8ca5ed4
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 149 deletions.
15 changes: 5 additions & 10 deletions lib/media_center/media_center_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ final selectedSongProvider = StateProvider.autoDispose<Song>((ref) {
return Song.empty();
}

Song editedSong = ref.read(editedSongProvider);
Song? editedSong = ref.read(editedSongProvider);

if (editedSong != Song.empty()) {
if (editedSong != null) {
return editedSong;
}

Expand Down Expand Up @@ -96,12 +96,7 @@ final playlistSelectedPreviewProvider = StateProvider.autoDispose<dynamic>((ref)
return null;
});

final isEditingProvider = StateProvider.autoDispose<bool>((ref) {
ref.watch(selectedSongProvider);

return false;
});

final editedSongProvider = StateProvider.autoDispose<Song>((ref) {
return Song.empty();
/// Highlights songs after editing
final editedSongProvider = StateProvider.autoDispose<Song?>((ref) {
return null;
});
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ class PlaylistPreviewPanelNotifier extends StateNotifier<Widget> {
}

void _previewSong(Song args) {
state = SongPreview(song: args);
state = SongPreview( args);
}
}
166 changes: 35 additions & 131 deletions lib/media_center/notifiers/song_editor_lyrics_fields_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,34 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freecps/core/file_utils.dart';

import '../../core/constants.dart';
import '../../core/helper_functions.dart';
import '../../models/song_model.dart';
import '../media_center_providers.dart';
import '../tabs/songs_tab.dart';
import '../widgets/song_editor_text_field_tile.dart';

/// Index of lyrics field and the position of the cursor in the field
typedef CursorLocation = ({int textFieldIndex, int cursorPosition});
typedef FieldData = ({TextEditingController controller, String label});

//TODO: MASSIVE MASSIVE REFACTOR

class SongEditorLyricsFieldsNotifier extends StateNotifier<Widget> {
SongEditorLyricsFieldsNotifier(this.song, this.ref) : super(Container()) {
init();
class SongEditorLyricsFieldsNotifier extends StateNotifier<List<SongEditorTextFieldTile>> {
SongEditorLyricsFieldsNotifier(this.song, this.ref) : super([]) {
_init();
}

final List<_SongEditorTextFieldTile> _fields = [];
final List<FieldData> _fieldsData = [];

Song song;

AutoDisposeStateNotifierProviderRef<SongEditorLyricsFieldsNotifier, Widget> ref;

CursorLocation? cursorLocation;
final AutoDisposeStateNotifierProviderRef<SongEditorLyricsFieldsNotifier, List<SongEditorTextFieldTile>> ref;
Song song;

TextEditingController titleController = TextEditingController();
TextEditingController artistController = TextEditingController();
final List<FieldData> _fieldsData = [];

void setCursorLocation({required int textFieldIndex, required int cursorPos}) {
cursorLocation = (textFieldIndex: textFieldIndex - 1, cursorPosition: cursorPos);
}

init() {
for (var entry in song.lyrics.entries) {
for (var element in entry.value) {
TextEditingController controller = TextEditingController.fromValue(TextEditingValue(text: element));
_fieldsData.add((controller: controller, label: entry.key));
}
}

titleController.text = song.title;
artistController.text = song.artist;

_setState();
}

insertSlide() {
// adds a field to the list
insertField() {
// if there are no fields, adds field to begin the list and return
if (_fieldsData.isEmpty) {
TextEditingController insertController = TextEditingController();

Expand All @@ -60,6 +41,10 @@ class SongEditorLyricsFieldsNotifier extends StateNotifier<Widget> {
return;
}

// if there are fields, insert a field to the cursor location
// splits the text based on the cursor
// puts text after the cursor into the newly inserted field

if (cursorLocation == null) return;

int index = cursorLocation!.textFieldIndex;
Expand All @@ -79,7 +64,10 @@ class SongEditorLyricsFieldsNotifier extends StateNotifier<Widget> {
_setState();
}

save() {
save({
required TextEditingController titleController,
required TextEditingController artistController,
}) {
if (titleController.text.isEmpty) return;
if (_fieldsData.isEmpty) return;

Expand Down Expand Up @@ -110,121 +98,37 @@ class SongEditorLyricsFieldsNotifier extends StateNotifier<Widget> {
bool isEditing = ref.read(isEditingProvider);

ref.read(isEditingProvider.notifier).state = !isEditing;

ref.read(editedSongProvider.notifier).state = song;
}

Widget _textFieldList() {
return Expanded(
child: ListView(
children: [
Row(
children: [
const Text('Title: '),
Flexible(
flex: 1,
child: Container(),
),
Flexible(
flex: 2,
child: TextField(
controller: titleController,
),
),
],
),
Row(
children: [
const Text('Artist: '),
const Spacer(
flex: 1,
),
Flexible(
flex: 2,
child: TextField(
controller: artistController,
),
),
],
),
..._fields,
],
),
);

/// initializes the fields
/// takes all labels, ie. Verses, Chorus, etc. and gets all lines of lyrics from each label
/// assigns each line to a corresponding field
_init() {
for (var entry in song.lyrics.entries) {
for (var element in entry.value) {
TextEditingController controller = TextEditingController.fromValue(TextEditingValue(text: element));
_fieldsData.add((controller: controller, label: entry.key));
}
}

_setState();
}

void _setState() {
_fields.clear();
state.clear();

for (int i = 0; i < _fieldsData.length; i++) {
FieldData fieldData = _fieldsData[i];

_fields.add(_SongEditorTextFieldTile(
state.add(SongEditorTextFieldTile(
label: fieldData.label,
controller: fieldData.controller,
index: i + 1,
));
}

state = _textFieldList();
}
}

class _SongEditorTextFieldTile extends ConsumerWidget {
const _SongEditorTextFieldTile({required this.label, required this.controller, required this.index});

final String label;
final TextEditingController controller;
final int index;

@override
Widget build(BuildContext context, WidgetRef ref) {
final Color color = catpuccinColorsSample[label] ?? Colors.blueGrey;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 100, vertical: 10),
shape: RoundedRectangleBorder(
side: BorderSide(
color: color,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 10),
color: color,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(index.toString()),
Text(label),
],
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
textAlign: TextAlign.center,
controller: controller,
minLines: 5,
maxLines: 10,
onTap: () {
ref.read(songEditorProvider.notifier).setCursorLocation(
textFieldIndex: index,
cursorPos: controller.selection.baseOffset,
);
},
onChanged: (input) {
ref.read(songEditorProvider.notifier).setCursorLocation(
textFieldIndex: index,
cursorPos: controller.selection.baseOffset,
);
},
),
),
],
),
);
state = state.toList();
}
}
62 changes: 56 additions & 6 deletions lib/media_center/tabs/songs_tab.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:freecps/media_center/widgets/song_preview.dart';

import '../../core/constants.dart';
Expand All @@ -11,13 +13,20 @@ import '../../models/song_slide_model.dart';
import '../../widgets/song_slide_widget.dart';
import '../media_center_providers.dart';
import '../notifiers/song_editor_lyrics_fields_notifier.dart';
import '../widgets/song_editor_text_field_tile.dart';

final songEditorProvider = StateNotifierProvider.autoDispose<SongEditorLyricsFieldsNotifier, Widget>((ref) {
final songEditorLyricsFieldProvider = StateNotifierProvider.autoDispose<SongEditorLyricsFieldsNotifier, List<SongEditorTextFieldTile>>((ref) {
Song song = ref.watch(selectedSongProvider);

return SongEditorLyricsFieldsNotifier(song, ref);
});

final isEditingProvider = StateProvider.autoDispose<bool>((ref) {
ref.watch(selectedSongProvider);

return false;
});

class SongsTab extends ConsumerWidget {
const SongsTab({
Key? key,
Expand Down Expand Up @@ -79,7 +88,7 @@ class SongsTab extends ConsumerWidget {
const VerticalDivider(),
Flexible(
flex: 2,
child: ref.watch(isEditingProvider) ? const _SongEditor() : SongPreview(song: selectedSong),
child: ref.watch(isEditingProvider) ? _SongEditor(selectedSong) : SongPreview(selectedSong),
),
const VerticalDivider(),
Flexible(
Expand Down Expand Up @@ -189,7 +198,12 @@ class _SongSlidePreview extends StatelessWidget {
}

class _SongEditor extends ConsumerWidget {
const _SongEditor();
_SongEditor(this.song);

final Song song;

late final TextEditingController titleController = TextEditingController(text: song.title);
late final TextEditingController artistController = TextEditingController(text: song.artist);

@override
Widget build(BuildContext context, WidgetRef ref) {
Expand All @@ -200,19 +214,55 @@ class _SongEditor extends ConsumerWidget {
children: [
ElevatedButton(
onPressed: () {
ref.read(songEditorProvider.notifier).insertSlide();
ref.read(songEditorLyricsFieldProvider.notifier).insertField();
},
child: const Text('Inser Slide in cursor position'),
),
ElevatedButton(
onPressed: () {
ref.read(songEditorProvider.notifier).save();
ref.read(songEditorLyricsFieldProvider.notifier).save(
titleController: titleController,
artistController: artistController,
);
},
child: const Text('Save song'),
),
],
),
ref.watch(songEditorProvider),
Row(
children: [
const Text('Title: '),
Flexible(
flex: 1,
child: Container(),
),
Flexible(
flex: 2,
child: TextField(
controller: titleController,
),
),
],
),
Row(
children: [
const Text('Artist: '),
const Spacer(
flex: 1,
),
Flexible(
flex: 2,
child: TextField(
controller: artistController,
),
),
],
),
Expanded(
child: ListView(
children: [...ref.watch(songEditorLyricsFieldProvider)],
),
),
],
);
}
Expand Down
Loading

0 comments on commit 8ca5ed4

Please sign in to comment.