Skip to content

Commit

Permalink
PAINTROID-454: Flutter: Add Layers
Browse files Browse the repository at this point in the history
  • Loading branch information
Lenkomotive committed Oct 9, 2024
1 parent ae20a51 commit b4d9680
Show file tree
Hide file tree
Showing 9 changed files with 358 additions and 79 deletions.
11 changes: 11 additions & 0 deletions lib/core/providers/state/layer_menu_state_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'layer_menu_state_data.freezed.dart';

@immutable
@freezed
class LayerMenuStateData with _$LayerMenuStateData {
const factory LayerMenuStateData({
required bool isVisible,
}) = _LayerMenuStateData;
}
135 changes: 135 additions & 0 deletions lib/core/providers/state/layer_menu_state_data.freezed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// 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 'layer_menu_state_data.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#adding-getters-and-methods-to-our-models');

/// @nodoc
mixin _$LayerMenuStateData {
bool get isVisible => throw _privateConstructorUsedError;

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

/// @nodoc
abstract class $LayerMenuStateDataCopyWith<$Res> {
factory $LayerMenuStateDataCopyWith(
LayerMenuStateData value, $Res Function(LayerMenuStateData) then) =
_$LayerMenuStateDataCopyWithImpl<$Res, LayerMenuStateData>;
@useResult
$Res call({bool isVisible});
}

/// @nodoc
class _$LayerMenuStateDataCopyWithImpl<$Res, $Val extends LayerMenuStateData>
implements $LayerMenuStateDataCopyWith<$Res> {
_$LayerMenuStateDataCopyWithImpl(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? isVisible = null,
}) {
return _then(_value.copyWith(
isVisible: null == isVisible
? _value.isVisible
: isVisible // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}

/// @nodoc
abstract class _$$LayerMenuStateDataImplCopyWith<$Res>
implements $LayerMenuStateDataCopyWith<$Res> {
factory _$$LayerMenuStateDataImplCopyWith(_$LayerMenuStateDataImpl value,
$Res Function(_$LayerMenuStateDataImpl) then) =
__$$LayerMenuStateDataImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({bool isVisible});
}

/// @nodoc
class __$$LayerMenuStateDataImplCopyWithImpl<$Res>
extends _$LayerMenuStateDataCopyWithImpl<$Res, _$LayerMenuStateDataImpl>
implements _$$LayerMenuStateDataImplCopyWith<$Res> {
__$$LayerMenuStateDataImplCopyWithImpl(_$LayerMenuStateDataImpl _value,
$Res Function(_$LayerMenuStateDataImpl) _then)
: super(_value, _then);

@pragma('vm:prefer-inline')
@override
$Res call({
Object? isVisible = null,
}) {
return _then(_$LayerMenuStateDataImpl(
isVisible: null == isVisible
? _value.isVisible
: isVisible // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}

/// @nodoc
class _$LayerMenuStateDataImpl implements _LayerMenuStateData {
const _$LayerMenuStateDataImpl({required this.isVisible});

@override
final bool isVisible;

@override
String toString() {
return 'LayerMenuStateData(isVisible: $isVisible)';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LayerMenuStateDataImpl &&
(identical(other.isVisible, isVisible) ||
other.isVisible == isVisible));
}

@override
int get hashCode => Object.hash(runtimeType, isVisible);

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

abstract class _LayerMenuStateData implements LayerMenuStateData {
const factory _LayerMenuStateData({required final bool isVisible}) =
_$LayerMenuStateDataImpl;

@override
bool get isVisible;
@override
@JsonKey(ignore: true)
_$$LayerMenuStateDataImplCopyWith<_$LayerMenuStateDataImpl> get copyWith =>
throw _privateConstructorUsedError;
}
18 changes: 18 additions & 0 deletions lib/core/providers/state/layer_menu_state_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:paintroid/core/providers/state/layer_menu_state_data.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'layer_menu_state_provider.g.dart';

@Riverpod(keepAlive: true)
class LayerMenuStateProvider extends _$LayerMenuStateProvider {
@override
LayerMenuStateData build() {
return const LayerMenuStateData(
isVisible: false,
);
}

void toggleVisibility() {
state = state.copyWith(isVisible: !state.isVisible);
}
}
27 changes: 27 additions & 0 deletions lib/core/providers/state/layer_menu_state_provider.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 58 additions & 52 deletions lib/ui/pages/workspace_page/components/bottom_bar/bottom_nav_bar.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import 'package:colorpicker/colorpicker.dart';
import 'package:flutter/material.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:colorpicker/colorpicker.dart';

import 'package:paintroid/core/enums/tool_types.dart';
import 'package:paintroid/core/localization/app_localizations.dart';
import 'package:paintroid/core/providers/state/layer_menu_state_provider.dart';
import 'package:paintroid/core/providers/state/paint_provider.dart';
import 'package:paintroid/core/providers/state/tool_options_visibility_state_provider.dart';
import 'package:paintroid/core/providers/state/toolbox_state_provider.dart';
Expand Down Expand Up @@ -78,59 +77,66 @@ class BottomNavBar extends ConsumerWidget {
);
return currentToolData;
}
}

void _onNavigationItemSelected(int index, BuildContext context, WidgetRef ref) {
BottomNavBarItem item = BottomNavBarItem.values[index];
switch (item) {
case BottomNavBarItem.TOOLS:
_showToolBottomSheet(context);
break;
case BottomNavBarItem.TOOL_OPTIONS:
_handleToolOptionsVisibility(ref);
break;
case BottomNavBarItem.COLOR:
_showColorPicker(context, ref);
break;
default:
return;
void _onNavigationItemSelected(
int index, BuildContext context, WidgetRef ref) {
BottomNavBarItem item = BottomNavBarItem.values[index];
switch (item) {
case BottomNavBarItem.TOOLS:
_showToolBottomSheet(context);
break;
case BottomNavBarItem.TOOL_OPTIONS:
_handleToolOptionsVisibility(ref);
break;
case BottomNavBarItem.COLOR:
_showColorPicker(context, ref);
break;
case BottomNavBarItem.LAYERS:
_showLayerMenu(context, ref);
default:
return;
}
}
}

void _showToolBottomSheet(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
showModalBottomSheet(
context: context,
builder: (BuildContext context) => SizedBox(
height: screenHeight * 0.5,
child: const ToolsBottomSheet(),
),
);
}
void _showToolBottomSheet(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
showModalBottomSheet(
context: context,
builder: (BuildContext context) => SizedBox(
height: screenHeight * 0.5,
child: const ToolsBottomSheet(),
),
);
}

void _handleToolOptionsVisibility(WidgetRef ref) {
ref.read(toolOptionsVisibilityStateProvider.notifier).toggleVisibility();
}
void _handleToolOptionsVisibility(WidgetRef ref) {
ref.read(toolOptionsVisibilityStateProvider.notifier).toggleVisibility();
}

void _showColorPicker(BuildContext context, WidgetRef ref) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext dialogContext) => Container(
height: MediaQuery.of(dialogContext).size.height * 0.7,
alignment: Alignment.center,
decoration: BoxDecoration(
color: PaintroidTheme.of(dialogContext).onSurfaceColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
)),
child: ColorPicker(
currentColor: ref.watch(paintProvider).color,
onColorChanged: (newColor) {
ref.watch(paintProvider.notifier).updateColor(newColor);
},
void _showColorPicker(BuildContext context, WidgetRef ref) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext dialogContext) => Container(
height: MediaQuery.of(dialogContext).size.height * 0.7,
alignment: Alignment.center,
decoration: BoxDecoration(
color: PaintroidTheme.of(dialogContext).onSurfaceColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
)),
child: ColorPicker(
currentColor: ref.watch(paintProvider).color,
onColorChanged: (newColor) {
ref.watch(paintProvider.notifier).updateColor(newColor);
},
),
),
),
);
);
}

void _showLayerMenu(BuildContext context, WidgetRef ref) {
ref.read(layerMenuStateProvider.notifier).toggleVisibility();
}
}
30 changes: 30 additions & 0 deletions lib/ui/pages/workspace_page/components/layer_menu/layer_menu.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:paintroid/core/providers/state/layer_menu_state_provider.dart';
import 'package:paintroid/ui/shared/fade_in_out_widget.dart';

class LayerMenu extends ConsumerWidget {
const LayerMenu({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final isVisible = ref.watch(
layerMenuStateProvider.select((state) => state.isVisible),
);
return Positioned(
top: 32,
bottom: 32,
right: 8,
child: FadeInOutWidget(
isVisible: isVisible,
child: Container(
width: 200,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
),
),
);
}
}
6 changes: 3 additions & 3 deletions lib/ui/pages/workspace_page/workspace_page.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:toast/toast.dart';

import 'package:paintroid/core/providers/object/io_handler.dart';
import 'package:paintroid/core/providers/state/workspace_state_notifier.dart';
import 'package:paintroid/ui/pages/workspace_page/components/bottom_bar/bottom_nav_bar.dart';
import 'package:paintroid/ui/pages/workspace_page/components/bottom_bar/tool_options/tool_options.dart';
import 'package:paintroid/ui/pages/workspace_page/components/drawing_surface/drawing_canvas.dart';
import 'package:paintroid/ui/pages/workspace_page/components/drawing_surface/exit_fullscreen_button.dart';
import 'package:paintroid/ui/pages/workspace_page/components/layer_menu/layer_menu.dart';
import 'package:paintroid/ui/pages/workspace_page/components/top_bar/top_app_bar.dart';
import 'package:paintroid/ui/shared/dialogs/discard_changes_dialog.dart';
import 'package:toast/toast.dart';

class WorkspacePage extends ConsumerStatefulWidget {
const WorkspacePage({super.key});
Expand Down Expand Up @@ -78,6 +77,7 @@ class _WorkspaceScreenState extends ConsumerState<WorkspacePage> {
)
else
const ToolOptions(),
const LayerMenu(),
],
),
bottomNavigationBar: isFullscreen ? null : const BottomNavBar(),
Expand Down
Loading

0 comments on commit b4d9680

Please sign in to comment.