Skip to content

Commit

Permalink
Add full screen button, prepare the save folder dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
Ellet committed Dec 27, 2023
1 parent c72ec6a commit 6ff171e
Show file tree
Hide file tree
Showing 17 changed files with 447 additions and 20 deletions.
16 changes: 16 additions & 0 deletions lib/data/note_folder/models/m_note_folder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'dart:io';

import 'package:freezed_annotation/freezed_annotation.dart';

import '../../notes/universal/models/m_note.dart';

part 'm_note_folder.freezed.dart';

@freezed
class NoteFolder with _$NoteFolder {
const factory NoteFolder({
required String folderName,
required List<Directory> folders,
required List<UniversalNote> notes,
}) = _NoteFolder;
}
190 changes: 190 additions & 0 deletions lib/data/note_folder/models/m_note_folder.freezed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark

part of 'm_note_folder.dart';

// **************************************************************************
// FreezedGenerator
// **************************************************************************

T _$identity<T>(T value) => value;

final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');

/// @nodoc
mixin _$NoteFolder {
String get folderName => throw _privateConstructorUsedError;
List<Directory> get folders => throw _privateConstructorUsedError;
List<UniversalNote> get notes => throw _privateConstructorUsedError;

@JsonKey(ignore: true)
$NoteFolderCopyWith<NoteFolder> get copyWith =>
throw _privateConstructorUsedError;
}

/// @nodoc
abstract class $NoteFolderCopyWith<$Res> {
factory $NoteFolderCopyWith(
NoteFolder value, $Res Function(NoteFolder) then) =
_$NoteFolderCopyWithImpl<$Res, NoteFolder>;
@useResult
$Res call(
{String folderName, List<Directory> folders, List<UniversalNote> notes});
}

/// @nodoc
class _$NoteFolderCopyWithImpl<$Res, $Val extends NoteFolder>
implements $NoteFolderCopyWith<$Res> {
_$NoteFolderCopyWithImpl(this._value, this._then);

// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;

@pragma('vm:prefer-inline')
@override
$Res call({
Object? folderName = null,
Object? folders = null,
Object? notes = null,
}) {
return _then(_value.copyWith(
folderName: null == folderName
? _value.folderName
: folderName // ignore: cast_nullable_to_non_nullable
as String,
folders: null == folders
? _value.folders
: folders // ignore: cast_nullable_to_non_nullable
as List<Directory>,
notes: null == notes
? _value.notes
: notes // ignore: cast_nullable_to_non_nullable
as List<UniversalNote>,
) as $Val);
}
}

/// @nodoc
abstract class _$$NoteFolderImplCopyWith<$Res>
implements $NoteFolderCopyWith<$Res> {
factory _$$NoteFolderImplCopyWith(
_$NoteFolderImpl value, $Res Function(_$NoteFolderImpl) then) =
__$$NoteFolderImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String folderName, List<Directory> folders, List<UniversalNote> notes});
}

/// @nodoc
class __$$NoteFolderImplCopyWithImpl<$Res>
extends _$NoteFolderCopyWithImpl<$Res, _$NoteFolderImpl>
implements _$$NoteFolderImplCopyWith<$Res> {
__$$NoteFolderImplCopyWithImpl(
_$NoteFolderImpl _value, $Res Function(_$NoteFolderImpl) _then)
: super(_value, _then);

@pragma('vm:prefer-inline')
@override
$Res call({
Object? folderName = null,
Object? folders = null,
Object? notes = null,
}) {
return _then(_$NoteFolderImpl(
folderName: null == folderName
? _value.folderName
: folderName // ignore: cast_nullable_to_non_nullable
as String,
folders: null == folders
? _value._folders
: folders // ignore: cast_nullable_to_non_nullable
as List<Directory>,
notes: null == notes
? _value._notes
: notes // ignore: cast_nullable_to_non_nullable
as List<UniversalNote>,
));
}
}

/// @nodoc
class _$NoteFolderImpl implements _NoteFolder {
const _$NoteFolderImpl(
{required this.folderName,
required final List<Directory> folders,
required final List<UniversalNote> notes})
: _folders = folders,
_notes = notes;

@override
final String folderName;
final List<Directory> _folders;
@override
List<Directory> get folders {
if (_folders is EqualUnmodifiableListView) return _folders;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_folders);
}

final List<UniversalNote> _notes;
@override
List<UniversalNote> get notes {
if (_notes is EqualUnmodifiableListView) return _notes;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_notes);
}

@override
String toString() {
return 'NoteFolder(folderName: $folderName, folders: $folders, notes: $notes)';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$NoteFolderImpl &&
(identical(other.folderName, folderName) ||
other.folderName == folderName) &&
const DeepCollectionEquality().equals(other._folders, _folders) &&
const DeepCollectionEquality().equals(other._notes, _notes));
}

@override
int get hashCode => Object.hash(
runtimeType,
folderName,
const DeepCollectionEquality().hash(_folders),
const DeepCollectionEquality().hash(_notes));

@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$NoteFolderImplCopyWith<_$NoteFolderImpl> get copyWith =>
__$$NoteFolderImplCopyWithImpl<_$NoteFolderImpl>(this, _$identity);
}

abstract class _NoteFolder implements NoteFolder {
const factory _NoteFolder(
{required final String folderName,
required final List<Directory> folders,
required final List<UniversalNote> notes}) = _$NoteFolderImpl;

@override
String get folderName;
@override
List<Directory> get folders;
@override
List<UniversalNote> get notes;
@override
@JsonKey(ignore: true)
_$$NoteFolderImplCopyWith<_$NoteFolderImpl> get copyWith =>
throw _privateConstructorUsedError;
}
48 changes: 48 additions & 0 deletions lib/logic/note_folder/cubit/note_folder_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'dart:io' show Directory;

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'
show getApplicationDocumentsDirectory;

import '../../../data/note_folder/models/m_note_folder.dart';
import '../../../data/notes/universal/models/m_note.dart';

part 'note_folder_state.dart';

class NoteFolderCubit extends Cubit<NoteFolderState> {
NoteFolderCubit() : super(const NoteFolderState(folders: []));

Future<void> getFolders() async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final noteFoldersDirectory =
Directory(path.join(documentsDirectory.path, 'note-folders'));
final folders = noteFoldersDirectory
.listSync()
.map(
(event) => NoteFolder(
folderName: path.basename(event.path),
folders: [],
notes: [
UniversalNote(
noteId: 'noteId',
userId: 'userId',
title: 'title',
text: 'text',
isSyncWithCloud: true,
isPrivate: false,
isTrash: false,
isFavorite: false,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
)
],
),
)
.toList();
emit(NoteFolderState(
folders: folders,
));
}
}
12 changes: 12 additions & 0 deletions lib/logic/note_folder/cubit/note_folder_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
part of 'note_folder_cubit.dart';

class NoteFolderState extends Equatable {
const NoteFolderState({required this.folders});

final List<NoteFolder> folders;

@override
List<Object?> get props => [
folders,
];
}
18 changes: 12 additions & 6 deletions lib/logic/utils/validators/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,37 @@ class AuthValidator {
static const _emailRegex =
'''[a-zA-Z0-9+._%-+]{1,256}@[a-zA-Z0-9][a-zA-Z0-9-]{0,64}(.[a-zA-Z0-9][a-zA-Z0-9-]{0,25})+''';

static String? validateEmail(String email) {
static String? validateEmail(
String email, {
required String pleaseEnterYourEmailAddress,
required String pleaseEnterAValidEmailAddress,
}) {
final validateNotTextHasError = GlobalValidator.validateTextIsEmpty(
email,
errorMessage: 'Please enter your email address.',
errorMessage: pleaseEnterYourEmailAddress,
);
if (validateNotTextHasError != null) {
return validateNotTextHasError;
}

if (!RegExp(_emailRegex).hasMatch(email)) {
return 'Please enter a valid email address.';
return pleaseEnterAValidEmailAddress;
}
return null;
}

static String? validatePassword(String password) {
static String? validatePassword(String password,
{required String pleaseEnterAPassword,
required String passwordShouldBeMoreThan6}) {
final validateNotTextHasError = GlobalValidator.validateTextIsEmpty(
password,
errorMessage: 'Please enter a password.',
errorMessage: pleaseEnterAPassword,
);
if (validateNotTextHasError != null) {
return validateNotTextHasError;
}
if (password.length < 6) {
return 'Password should be at least 6 characters.';
return passwordShouldBeMoreThan6;
}

return null;
Expand Down
7 changes: 6 additions & 1 deletion lib/presentation/components/auth/w_email_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ class EmailTextField extends StatelessWidget {
labelText: context.loc.emailAddress,
),
validator: (email) {
final errorMessage = AuthValidator.validateEmail(email ?? '');
final errorMessage = AuthValidator.validateEmail(
email ?? '',
pleaseEnterYourEmailAddress: context.loc.pleaseEnterYourEmailAddress,
pleaseEnterAValidEmailAddress:
context.loc.pleaseEnterAValidEmailAddress,
);
if (errorMessage != null) {
return errorMessage;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/presentation/components/auth/w_password_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class _PasswordTextFieldState extends State<PasswordTextField> {
validator: (password) {
final errorMessage = AuthValidator.validatePassword(
password ?? '',
passwordShouldBeMoreThan6: context.loc.pleaseEnterAPassword,
pleaseEnterAPassword:
context.loc.thePasswordShouldBeMoreThan6Characters,
);
if (errorMessage != null) {
return errorMessage;
Expand Down
48 changes: 48 additions & 0 deletions lib/presentation/components/note/toolbar/buttons/full_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show SystemChrome, SystemUiMode;

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

@override
State<NoteToolbarFullScreenButton> createState() =>
_NoteToolbarFullScreenButtonState();
}

class _NoteToolbarFullScreenButtonState
extends State<NoteToolbarFullScreenButton> {
var _isFullScreen = false;

@override
void dispose() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);

super.dispose();
}

@override
Widget build(BuildContext context) {
if (_isFullScreen) {
return IconButton.filled(
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);

setState(() {
_isFullScreen = false;
});
},
icon: const Icon(Icons.fullscreen),
);
}
return IconButton(
onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);

setState(() {
_isFullScreen = true;
});
},
icon: const Icon(Icons.fullscreen_exit),
);
}
}
Loading

0 comments on commit 6ff171e

Please sign in to comment.