From c61558d616751eee873b72b8e07735d3de29e64b Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Wed, 1 Sep 2021 09:09:38 -0700 Subject: [PATCH 1/2] dart format --- .../_internal/components/animated_panel.dart | 42 ++++- .../_internal/components/animated_state.dart | 6 +- .../components/clickable_extensions.dart | 2 +- .../components/content_underlay.dart | 5 +- .../_internal/components/delayed_builder.dart | 9 +- .../components/design_grid_overlay.dart | 15 +- .../components/mouse_hover_builder.dart | 7 +- .../components/multi_value_listenable.dart | 26 ++- .../components/no_glow_scroll_behavior.dart | 3 +- .../_internal/components/one_line_text.dart | 5 +- .../lib/_internal/components/pinned.dart | 22 ++- .../_internal/components/pinned_stack.dart | 6 +- .../lib/_internal/components/rotation_3d.dart | 7 +- .../components/scrolling_flex_view.dart | 8 +- .../components/selectable_link_text.dart | 12 +- .../components/translate_and_align.dart | 3 +- flokk_src/lib/_internal/http_client.dart | 27 ++- flokk_src/lib/_internal/log.dart | 8 +- flokk_src/lib/_internal/page_routes.dart | 20 ++- flokk_src/lib/_internal/pointer_blocker.dart | 3 +- .../universal_file/universal_file.dart | 4 +- .../universal_file_locator.dart | 4 +- .../_internal/universal_file/web_file.dart | 6 +- .../universal_picker/desktop_picker.dart | 3 +- .../universal_picker/universal_picker.dart | 3 +- .../universal_picker_locator.dart | 5 +- .../universal_picker/web_picker.dart | 6 +- .../_internal/url_launcher/url_launcher.dart | 9 +- .../url_launcher/url_launcher_locator.dart | 3 +- .../lib/_internal/utils/build_utils.dart | 12 +- .../lib/_internal/utils/color_utils.dart | 12 +- flokk_src/lib/_internal/utils/picker.dart | 6 +- .../lib/_internal/utils/string_utils.dart | 18 +- flokk_src/lib/_internal/utils/utils.dart | 6 +- flokk_src/lib/commands/abstract_command.dart | 6 +- flokk_src/lib/commands/bootstrap_command.dart | 10 +- .../commands/check_connection_command.dart | 3 +- .../contacts/delete_contact_command.dart | 19 +- .../commands/contacts/delete_pic_command.dart | 9 +- .../contacts/refresh_contacts_command.dart | 10 +- .../contacts/toggle_favorite_command.dart | 10 +- .../contacts/update_contact_command.dart | 15 +- .../commands/contacts/update_pic_command.dart | 10 +- .../dialogs/show_discard_warning_command.dart | 3 +- .../dialogs/show_service_error_command.dart | 9 +- .../groups/add_label_to_contact_command.dart | 9 +- .../commands/groups/create_label_command.dart | 6 +- .../commands/groups/delete_label_command.dart | 6 +- .../refresh_contact_groups_command.dart | 33 ++-- .../remove_label_from_contact_command.dart | 7 +- .../commands/groups/rename_label_command.dart | 6 +- .../groups/update_contact_labels_command.dart | 20 ++- flokk_src/lib/commands/logout_command.dart | 3 +- .../commands/refresh_auth_tokens_command.dart | 6 +- .../social/refresh_github_command.dart | 17 +- .../social/refresh_social_command.dart | 20 ++- .../social/refresh_twitter_command.dart | 19 +- .../commands/social/test_repeat_command.dart | 4 +- .../lib/commands/web_sign_in_command.dart | 6 +- flokk_src/lib/data/contact_data.dart | 47 +++-- flokk_src/lib/data/git_event_data.dart | 5 +- flokk_src/lib/data/git_repo_data.dart | 11 +- flokk_src/lib/data/group_data.dart | 5 +- flokk_src/lib/data/social_contact_data.dart | 28 +-- flokk_src/lib/data/tweet_data.dart | 2 +- flokk_src/lib/data/twitter_user_data.dart | 3 +- flokk_src/lib/main.dart | 13 +- flokk_src/lib/models/abstract_model.dart | 12 +- flokk_src/lib/models/app_model.dart | 19 +- flokk_src/lib/models/auth_model.dart | 4 +- flokk_src/lib/models/contacts_model.dart | 87 ++++++--- flokk_src/lib/models/github_model.dart | 43 +++-- flokk_src/lib/models/twitter_model.dart | 25 ++- .../lib/services/github_rest_service.dart | 15 +- .../google_rest/google_rest_auth_service.dart | 25 ++- .../google_rest_contact_groups_service.dart | 27 ++- .../google_rest_contacts_service.dart | 92 ++++++---- .../google_rest/google_rest_service.dart | 6 +- .../lib/services/twitter_rest_service.dart | 21 ++- flokk_src/lib/strings.dart | 21 ++- .../buttons/base_styled_button.dart | 15 +- .../buttons/colored_icon_btn.dart | 2 +- .../buttons/ok_cancel_btn_row.dart | 13 +- .../buttons/primary_btn.dart | 15 +- .../buttons/secondary_btn.dart | 9 +- .../buttons/transparent_btn.dart | 32 +++- .../styled_components/clickable_icon_row.dart | 20 ++- .../lib/styled_components/clickable_text.dart | 7 +- .../lib/styled_components/design_grid.dart | 7 +- .../lib/styled_components/flokk_logo.dart | 9 +- .../styled_components/opening_divider.dart | 4 +- .../styled_horizontal_scroll_view.dart | 15 +- .../scrolling/styled_listview.dart | 15 +- .../scrolling/styled_scrollbar.dart | 44 +++-- .../scrolling/styled_scrollview.dart | 4 +- .../social/clickable_social_badges.dart | 34 ++-- .../social/git_item_renderer.dart | 41 +++-- .../social/social_badge.dart | 14 +- .../social/social_popup_form.dart | 45 +++-- .../social/tweet_item_renderer.dart | 22 ++- .../styled_autocomplete_dropdown.dart | 52 ++++-- .../lib/styled_components/styled_card.dart | 11 +- .../styled_components/styled_checkbox.dart | 25 ++- .../styled_components/styled_container.dart | 5 +- .../lib/styled_components/styled_dialogs.dart | 26 ++- .../styled_form_label_input.dart | 17 +- .../styled_components/styled_group_label.dart | 18 +- .../lib/styled_components/styled_icons.dart | 72 +++++--- .../styled_components/styled_image_icon.dart | 4 +- .../styled_components/styled_label_pill.dart | 16 +- .../styled_progress_spinner.dart | 6 +- .../lib/styled_components/styled_tab_bar.dart | 16 +- .../styled_components/styled_text_input.dart | 21 ++- .../styled_components/styled_user_avatar.dart | 10 +- .../styled_components/textinput_icon_row.dart | 7 +- flokk_src/lib/styles.dart | 14 +- flokk_src/lib/tests/button_tests.dart | 16 +- .../lib/tests/command_testing_spike.dart | 38 ++-- flokk_src/lib/themes.dart | 3 +- .../contact_edit/contact_edit_panel.dart | 18 +- .../contact_edit/contact_edit_panel_view.dart | 19 +- .../expanding_miniform_container.dart | 13 +- .../miniforms/address_miniform.dart | 92 +++++----- .../contact_edit/miniforms/base_miniform.dart | 63 ++++--- .../miniforms/birthday_miniform.dart | 3 +- .../textfield_with_date_picker_row.dart | 12 +- .../miniforms/email_miniform.dart | 6 +- .../miniforms/events_miniform.dart | 28 +-- .../contact_edit/miniforms/job_miniform.dart | 10 +- .../miniforms/label_miniform.dart | 18 +- .../contact_edit/miniforms/name_miniform.dart | 23 ++- .../miniforms/notes_miniform.dart | 3 +- .../miniforms/phone_miniform.dart | 17 +- .../miniforms/relationship_miniform.dart | 3 +- .../miniforms/social_miniforms.dart | 22 ++- .../miniforms/website_miniform.dart | 6 +- .../contact_info_details_card.dart | 44 +++-- .../contact_info_header_card.dart | 19 +- .../contact_info/contact_info_panel.dart | 40 +++-- .../contact_info_social_card.dart | 13 +- .../contact_page/bulk_contact_edit_bar.dart | 33 +++- .../views/contact_page/contacts_list_row.dart | 73 ++++++-- .../contacts_list_with_headers.dart | 35 ++-- .../lib/views/contact_page/contacts_page.dart | 16 +- .../views/dashboard_page/dashboard_page.dart | 11 +- .../dates/important_date_card.dart | 13 +- .../dates/important_dates_section.dart | 10 +- .../social/responsive_double_list.dart | 10 +- .../social/social_activities_section.dart | 66 +++++-- .../social/tabbed_list_view.dart | 46 +++-- .../top/small_contact_card.dart | 6 +- .../top/top_contacts_section.dart | 44 +++-- .../placeholder_contact_list.dart | 33 ++-- .../placeholder_content_switcher.dart | 2 +- .../views/empty_states/placeholder_git.dart | 19 +- .../placeholder_important_dates.dart | 2 +- .../placeholder_top_contacts.dart | 17 +- .../empty_states/placeholder_twitter.dart | 16 +- .../placeholder_widget_helpers.dart | 15 +- .../views/main_scaffold/contact_panel.dart | 13 +- .../light_dark_toggle_switch.dart | 13 +- .../views/main_scaffold/main_scaffold.dart | 17 +- .../main_scaffold/main_scaffold_view.dart | 58 ++++-- .../views/main_scaffold/main_side_menu.dart | 170 ++++++++++-------- .../main_scaffold/main_side_menu_btn.dart | 39 ++-- flokk_src/lib/views/search/search_bar.dart | 13 +- .../lib/views/search/search_bar_view.dart | 18 +- flokk_src/lib/views/search/search_engine.dart | 39 ++-- .../views/search/search_query_results.dart | 37 +++- .../lib/views/search/search_query_row.dart | 38 ++-- .../views/welcome/animated_bird_splash.dart | 21 ++- .../welcome/animated_bird_splash_clipper.dart | 35 ++-- flokk_src/lib/views/welcome/welcome_page.dart | 34 +++- .../lib/views/welcome/welcome_page_step1.dart | 15 +- .../lib/views/welcome/welcome_page_step2.dart | 29 ++- 175 files changed, 2312 insertions(+), 1070 deletions(-) diff --git a/flokk_src/lib/_internal/components/animated_panel.dart b/flokk_src/lib/_internal/components/animated_panel.dart index 6f58d73..f8e91a4 100644 --- a/flokk_src/lib/_internal/components/animated_panel.dart +++ b/flokk_src/lib/_internal/components/animated_panel.dart @@ -38,8 +38,11 @@ class _AnimatedPanelState extends State { ), duration: Duration(milliseconds: (duration * 1000).round()), builder: (_, Offset value, Widget? c) { - _isHidden = c == null || widget.isClosed && value == Offset(widget.closedX, widget.closedY); - return _isHidden ? Container() : Transform.translate(offset: value, child: c); + _isHidden = c == null || + widget.isClosed && value == Offset(widget.closedX, widget.closedY); + return _isHidden + ? Container() + : Transform.translate(offset: value, child: c); }, child: widget.child, ); @@ -48,17 +51,38 @@ class _AnimatedPanelState extends State { extension AnimatedPanelExtensions on Widget { Widget animatedPanelX( - {double closeX = 0, bool isClosed = false, double duration = .35, Curve curve = Curves.easeOut}) => - animatedPanel(closePos: Offset(closeX, 0), isClosed: isClosed, curve: curve, duration: duration); + {double closeX = 0, + bool isClosed = false, + double duration = .35, + Curve curve = Curves.easeOut}) => + animatedPanel( + closePos: Offset(closeX, 0), + isClosed: isClosed, + curve: curve, + duration: duration); Widget animatedPanelY( - {double closeY = 0, bool isClosed = false, double duration = .35, Curve curve = Curves.easeOut}) => - animatedPanel(closePos: Offset(0, closeY), isClosed: isClosed, curve: curve, duration: duration); + {double closeY = 0, + bool isClosed = false, + double duration = .35, + Curve curve = Curves.easeOut}) => + animatedPanel( + closePos: Offset(0, closeY), + isClosed: isClosed, + curve: curve, + duration: duration); Widget animatedPanel( - {Offset closePos = Offset.zero, bool isClosed = false, double duration = .35, Curve curve = Curves.easeOut}) { + {Offset closePos = Offset.zero, + bool isClosed = false, + double duration = .35, + Curve curve = Curves.easeOut}) { return AnimatedPanel( - closedX: closePos.dx, closedY: closePos.dy, child: this, isClosed: isClosed, duration: duration, curve: curve); + closedX: closePos.dx, + closedY: closePos.dy, + child: this, + isClosed: isClosed, + duration: duration, + curve: curve); } } - diff --git a/flokk_src/lib/_internal/components/animated_state.dart b/flokk_src/lib/_internal/components/animated_state.dart index da835dd..285eaf8 100644 --- a/flokk_src/lib/_internal/components/animated_state.dart +++ b/flokk_src/lib/_internal/components/animated_state.dart @@ -21,10 +21,12 @@ class _AnimatedTextSpikeState extends AnimatedState { } } -abstract class AnimatedState extends State with SingleTickerProviderStateMixin { +abstract class AnimatedState extends State + with SingleTickerProviderStateMixin { late AnimationController animation; - AnimationController createAnim({double lowerBound = 0, double upperBound = 1, double seconds = .2}) { + AnimationController createAnim( + {double lowerBound = 0, double upperBound = 1, double seconds = .2}) { return AnimationController( vsync: this, duration: Duration(milliseconds: (seconds * 1000).round()), diff --git a/flokk_src/lib/_internal/components/clickable_extensions.dart b/flokk_src/lib/_internal/components/clickable_extensions.dart index 4c22bed..c0231d9 100644 --- a/flokk_src/lib/_internal/components/clickable_extensions.dart +++ b/flokk_src/lib/_internal/components/clickable_extensions.dart @@ -4,7 +4,7 @@ import 'package:flutter/rendering.dart'; extension ClickableExtensions on Widget { Widget clickable(void Function() action, {bool opaque = true}) { return GestureDetector( - behavior: opaque? HitTestBehavior.opaque : HitTestBehavior.deferToChild, + behavior: opaque ? HitTestBehavior.opaque : HitTestBehavior.deferToChild, onTap: action, child: MouseRegion( cursor: SystemMouseCursors.click, diff --git a/flokk_src/lib/_internal/components/content_underlay.dart b/flokk_src/lib/_internal/components/content_underlay.dart index 36927c5..b9eaf0f 100644 --- a/flokk_src/lib/_internal/components/content_underlay.dart +++ b/flokk_src/lib/_internal/components/content_underlay.dart @@ -6,7 +6,10 @@ class ContentUnderlay extends StatelessWidget { final Duration duration; const ContentUnderlay( - {Key? key, this.color = Colors.black87, this.isActive = true, this.duration = const Duration(milliseconds: 350)}) + {Key? key, + this.color = Colors.black87, + this.isActive = true, + this.duration = const Duration(milliseconds: 350)}) : super(key: key); @override diff --git a/flokk_src/lib/_internal/components/delayed_builder.dart b/flokk_src/lib/_internal/components/delayed_builder.dart index 87f1e56..8059496 100644 --- a/flokk_src/lib/_internal/components/delayed_builder.dart +++ b/flokk_src/lib/_internal/components/delayed_builder.dart @@ -6,7 +6,11 @@ class DelayedBuilder extends StatefulWidget { final WidgetBuilder secondBuilder; final double delay; - const DelayedBuilder({Key? key, required this.firstBuilder, required this.secondBuilder, this.delay = 0.0}) + const DelayedBuilder( + {Key? key, + required this.firstBuilder, + required this.secondBuilder, + this.delay = 0.0}) : super(key: key); @override @@ -27,5 +31,6 @@ class _DelayedBuilderState extends State { } @override - Widget build(BuildContext context) => !show ? widget.firstBuilder(context) : widget.secondBuilder(context); + Widget build(BuildContext context) => + !show ? widget.firstBuilder(context) : widget.secondBuilder(context); } diff --git a/flokk_src/lib/_internal/components/design_grid_overlay.dart b/flokk_src/lib/_internal/components/design_grid_overlay.dart index fba4083..0e672f5 100644 --- a/flokk_src/lib/_internal/components/design_grid_overlay.dart +++ b/flokk_src/lib/_internal/components/design_grid_overlay.dart @@ -7,7 +7,11 @@ class GridLayout { final int numCols; final double breakPt; - GridLayout({this.gutters = EdgeInsets.zero, this.padding = 0, this.numCols = 0, this.breakPt = 0}); + GridLayout( + {this.gutters = EdgeInsets.zero, + this.padding = 0, + this.numCols = 0, + this.breakPt = 0}); } class DesignGridOverlay extends StatefulWidget { @@ -50,7 +54,8 @@ class _DesignGridOverlayState extends State { : widget.child; } - void handleTap() => setState(() => gridAlpha >= 1 ? gridAlpha = 0 : gridAlpha += .48); + void handleTap() => + setState(() => gridAlpha >= 1 ? gridAlpha = 0 : gridAlpha += .48); } class _DesignGridView extends StatelessWidget { @@ -72,8 +77,10 @@ class _DesignGridView extends StatelessWidget { final List content = [Container(width: grid.padding)]; final int numCols = grid.numCols; for (var i = numCols; i-- > 0;) { - content.add( - Flexible(child: Container(color: Colors.red.withOpacity(state.gridAlpha * .4), height: double.infinity))); + content.add(Flexible( + child: Container( + color: Colors.red.withOpacity(state.gridAlpha * .4), + height: double.infinity))); content.add(Container(width: grid.padding)); } print("CurrentBreak: ${grid.breakPt}"); diff --git a/flokk_src/lib/_internal/components/mouse_hover_builder.dart b/flokk_src/lib/_internal/components/mouse_hover_builder.dart index c896863..250abba 100644 --- a/flokk_src/lib/_internal/components/mouse_hover_builder.dart +++ b/flokk_src/lib/_internal/components/mouse_hover_builder.dart @@ -6,7 +6,8 @@ typedef Widget HoverBuilder(BuildContext context, bool isHovering); class MouseHoverBuilder extends StatefulWidget { final bool isClickable; - MouseHoverBuilder({Key? key, required this.builder, this.isClickable = false}) : super(key: key); + MouseHoverBuilder({Key? key, required this.builder, this.isClickable = false}) + : super(key: key); final HoverBuilder builder; @@ -20,7 +21,9 @@ class _MouseHoverBuilderState extends State { @override Widget build(BuildContext context) { return MouseRegion( - cursor: widget.isClickable? SystemMouseCursors.click : SystemMouseCursors.basic, + cursor: widget.isClickable + ? SystemMouseCursors.click + : SystemMouseCursors.basic, onEnter: (p) => setOver(true), onExit: (p) => setOver(false), child: widget.builder(context, isOver), diff --git a/flokk_src/lib/_internal/components/multi_value_listenable.dart b/flokk_src/lib/_internal/components/multi_value_listenable.dart index 41fb59d..c187973 100644 --- a/flokk_src/lib/_internal/components/multi_value_listenable.dart +++ b/flokk_src/lib/_internal/components/multi_value_listenable.dart @@ -2,7 +2,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class ValueListenableBuilder2 extends StatelessWidget { - ValueListenableBuilder2({Key? key, required this.value1, required this.value2, required this.builder, this.child}) : super(key: key); + ValueListenableBuilder2( + {Key? key, + required this.value1, + required this.value2, + required this.builder, + this.child}) + : super(key: key); final ValueListenable value1; final ValueListenable value2; @@ -22,13 +28,21 @@ class ValueListenableBuilder2 extends StatelessWidget { } class ValueListenableBuilder3 extends StatelessWidget { - ValueListenableBuilder3({Key? key, required this.value1, required this.value2, required this.value3, required this.builder, this.child}) : super(key: key); + ValueListenableBuilder3( + {Key? key, + required this.value1, + required this.value2, + required this.value3, + required this.builder, + this.child}) + : super(key: key); final ValueListenable value1; final ValueListenable value2; final ValueListenable value3; final Widget? child; - final Widget Function(BuildContext context, A a, B b, C c, Widget? child) builder; + final Widget Function(BuildContext context, A a, B b, C c, Widget? child) + builder; @override Widget build(BuildContext context) { @@ -44,7 +58,8 @@ class ValueListenableBuilder3 extends StatelessWidget { } class ValueListenableBuilder4 extends StatelessWidget { - ValueListenableBuilder4(this.value1, this.value2, this.value3, this.value4, {Key? key, required this.builder, this.child}) + ValueListenableBuilder4(this.value1, this.value2, this.value3, this.value4, + {Key? key, required this.builder, this.child}) : super(key: key); final ValueListenable value1; @@ -53,7 +68,8 @@ class ValueListenableBuilder4 extends StatelessWidget { final ValueListenable value4; final Widget? child; - final Widget Function(BuildContext context, A a, B b, C c, D d, Widget? child) builder; + final Widget Function(BuildContext context, A a, B b, C c, D d, Widget? child) + builder; @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/_internal/components/no_glow_scroll_behavior.dart b/flokk_src/lib/_internal/components/no_glow_scroll_behavior.dart index 4482df9..2e62285 100644 --- a/flokk_src/lib/_internal/components/no_glow_scroll_behavior.dart +++ b/flokk_src/lib/_internal/components/no_glow_scroll_behavior.dart @@ -2,7 +2,8 @@ import 'package:flutter/material.dart'; class NoGlowScrollBehavior extends ScrollBehavior { @override - Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) { + Widget buildViewportChrome( + BuildContext context, Widget child, AxisDirection axisDirection) { return child; } } diff --git a/flokk_src/lib/_internal/components/one_line_text.dart b/flokk_src/lib/_internal/components/one_line_text.dart index 3b7902a..aa55f39 100644 --- a/flokk_src/lib/_internal/components/one_line_text.dart +++ b/flokk_src/lib/_internal/components/one_line_text.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; class OneLineText extends StatelessWidget { @@ -8,6 +7,6 @@ class OneLineText extends StatelessWidget { const OneLineText(this.text, {Key? key, this.style}) : super(key: key); @override - Widget build(BuildContext context) => - Text(text, style: style, maxLines: 1, softWrap: false, overflow: TextOverflow.fade); + Widget build(BuildContext context) => Text(text, + style: style, maxLines: 1, softWrap: false, overflow: TextOverflow.fade); } diff --git a/flokk_src/lib/_internal/components/pinned.dart b/flokk_src/lib/_internal/components/pinned.dart index 29ed38a..93b7dda 100644 --- a/flokk_src/lib/_internal/components/pinned.dart +++ b/flokk_src/lib/_internal/components/pinned.dart @@ -12,7 +12,13 @@ class Pin { final double? sizePx; final double? centerPct; - const Pin({this.startPx, this.startPct, this.endPx, this.endPct, this.sizePx, this.centerPct}); + const Pin( + {this.startPx, + this.startPct, + this.endPx, + this.endPct, + this.sizePx, + this.centerPct}); } class Pinned extends StatelessWidget { @@ -20,7 +26,8 @@ class Pinned extends StatelessWidget { final Pin vtPin; final Widget? child; - const Pinned({Key? key, required this.hzPin, required this.vtPin, this.child}) : super(key: key); + const Pinned({Key? key, required this.hzPin, required this.vtPin, this.child}) + : super(key: key); _Span calculateSpanFromPin(Pin pin, double maxSize) { var s = _Span(); @@ -59,7 +66,8 @@ class Pinned extends StatelessWidget { @override Widget build(BuildContext context) { //Check to see if we have been provided some StackConstraints by [ PinnedStack ] - StackConstraints? constraints = context.dependOnInheritedWidgetOfExactType(); + StackConstraints? constraints = + context.dependOnInheritedWidgetOfExactType(); if (constraints != null) { return _buildContent(constraints.constraints); } @@ -80,7 +88,10 @@ class Pinned extends StatelessWidget { offset: Offset(hzSpan.start, vtSpan.start), child: Align( alignment: Alignment.topLeft, - child: SizedBox(width: hzSpan.size, height: vtSpan.size, child: showChild ? child : null), + child: SizedBox( + width: hzSpan.size, + height: vtSpan.size, + child: showChild ? child : null), ), ); } @@ -94,5 +105,6 @@ class _Span { } extension PinnedExtensions on Widget { - Pinned pin({required Pin hz, required Pin vt}) => Pinned(hzPin: hz, vtPin: vt, child: this); + Pinned pin({required Pin hz, required Pin vt}) => + Pinned(hzPin: hz, vtPin: vt, child: this); } diff --git a/flokk_src/lib/_internal/components/pinned_stack.dart b/flokk_src/lib/_internal/components/pinned_stack.dart index cbfbf05..f78d1e5 100644 --- a/flokk_src/lib/_internal/components/pinned_stack.dart +++ b/flokk_src/lib/_internal/components/pinned_stack.dart @@ -3,12 +3,14 @@ import 'package:flutter/material.dart'; class StackConstraints extends InheritedWidget { final BoxConstraints constraints; - StackConstraints({required this.constraints, required Widget child}) : super(child: child); + StackConstraints({required this.constraints, required Widget child}) + : super(child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) { var old = (oldWidget as StackConstraints).constraints; - return old.maxWidth != constraints.maxWidth || old.maxHeight != constraints.maxHeight; + return old.maxWidth != constraints.maxWidth || + old.maxHeight != constraints.maxHeight; } } diff --git a/flokk_src/lib/_internal/components/rotation_3d.dart b/flokk_src/lib/_internal/components/rotation_3d.dart index e14bc5d..ed0e4f9 100644 --- a/flokk_src/lib/_internal/components/rotation_3d.dart +++ b/flokk_src/lib/_internal/components/rotation_3d.dart @@ -12,7 +12,12 @@ class Rotation3d extends StatelessWidget { final double rotationY; final double rotationZ; - const Rotation3d({Key? key, required this.child, this.rotationX = 0, this.rotationY = 0, this.rotationZ = 0}) + const Rotation3d( + {Key? key, + required this.child, + this.rotationX = 0, + this.rotationY = 0, + this.rotationZ = 0}) : super(key: key); @override diff --git a/flokk_src/lib/_internal/components/scrolling_flex_view.dart b/flokk_src/lib/_internal/components/scrolling_flex_view.dart index 92db89f..d4a9061 100644 --- a/flokk_src/lib/_internal/components/scrolling_flex_view.dart +++ b/flokk_src/lib/_internal/components/scrolling_flex_view.dart @@ -8,7 +8,10 @@ class ConstrainedFlexView extends StatelessWidget { final EdgeInsets scrollPadding; const ConstrainedFlexView(this.minSize, - {Key? key, required this.child, this.axis = Axis.vertical, this.scrollPadding = const EdgeInsets.all(0)}) + {Key? key, + required this.child, + this.axis = Axis.vertical, + this.scrollPadding = const EdgeInsets.all(0)}) : super(key: key); bool get isHz => axis == Axis.horizontal; @@ -25,7 +28,8 @@ class ConstrainedFlexView extends StatelessWidget { axis: axis, child: ConstrainedBox( constraints: BoxConstraints( - maxHeight: isHz ? double.infinity : minSize, maxWidth: isHz ? minSize : double.infinity), + maxHeight: isHz ? double.infinity : minSize, + maxWidth: isHz ? minSize : double.infinity), child: child, ), ), diff --git a/flokk_src/lib/_internal/components/selectable_link_text.dart b/flokk_src/lib/_internal/components/selectable_link_text.dart index 1031c67..df8b0e6 100644 --- a/flokk_src/lib/_internal/components/selectable_link_text.dart +++ b/flokk_src/lib/_internal/components/selectable_link_text.dart @@ -21,7 +21,8 @@ class SelectableLinkText extends StatefulWidget { } class _LinkTextState extends State { - List _gestureRecognizers = const []; + List _gestureRecognizers = + const []; final RegExp _regex = RegExp( r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%.,_\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\,+.~#?&//=]*)"); @@ -46,7 +47,8 @@ class _LinkTextState extends State { final themeData = Theme.of(context); final textStyle = widget.textStyle ?? themeData.textTheme.bodyText1; final linkStyle = widget.linkStyle ?? - themeData.textTheme.bodyText1?.copyWith(color: themeData.accentColor, decoration: TextDecoration.underline); + themeData.textTheme.bodyText1?.copyWith( + color: themeData.accentColor, decoration: TextDecoration.underline); final links = _regex.allMatches(widget.text); @@ -62,7 +64,8 @@ class _LinkTextState extends State { textSpans.add(TextSpan(text: part, style: textStyle)); if (i < links.length) { final link = links.elementAt(i).group(0) ?? ""; - final recognizer = TapGestureRecognizer()..onTap = () => _launchUrl(link); + final recognizer = TapGestureRecognizer() + ..onTap = () => _launchUrl(link); _gestureRecognizers.add(recognizer); textSpans.add( TextSpan(text: link, style: linkStyle, recognizer: recognizer), @@ -71,6 +74,7 @@ class _LinkTextState extends State { } }); - return RichText(text: TextSpan(children: textSpans), textAlign: widget.textAlign); + return RichText( + text: TextSpan(children: textSpans), textAlign: widget.textAlign); } } diff --git a/flokk_src/lib/_internal/components/translate_and_align.dart b/flokk_src/lib/_internal/components/translate_and_align.dart index 866f6f2..bb344d4 100644 --- a/flokk_src/lib/_internal/components/translate_and_align.dart +++ b/flokk_src/lib/_internal/components/translate_and_align.dart @@ -5,7 +5,8 @@ class TranslateAndAlign extends StatelessWidget { final Alignment align; final Widget? child; - TranslateAndAlign({this.child, this.offset = Offset.zero, this.align = Alignment.topLeft}); + TranslateAndAlign( + {this.child, this.offset = Offset.zero, this.align = Alignment.topLeft}); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/_internal/http_client.dart b/flokk_src/lib/_internal/http_client.dart index 78c2981..41c63c4 100644 --- a/flokk_src/lib/_internal/http_client.dart +++ b/flokk_src/lib/_internal/http_client.dart @@ -14,38 +14,46 @@ enum NetErrorType { typedef Future HttpRequest(); class HttpClient { - static Future get(String url, {Map? headers}) async { + static Future get(String url, + {Map? headers}) async { return await _request(() async { return await http.get(Uri.parse(url), headers: headers); }); } - static Future post(String url, {Map? headers, dynamic body, Encoding? encoding}) async { + static Future post(String url, + {Map? headers, dynamic body, Encoding? encoding}) async { return await _request(() async { - return await http.post(Uri.parse(url), headers: headers, body: body, encoding: encoding); + return await http.post(Uri.parse(url), + headers: headers, body: body, encoding: encoding); }); } - static Future put(String url, {Map? headers, dynamic body, Encoding? encoding}) async { + static Future put(String url, + {Map? headers, dynamic body, Encoding? encoding}) async { return await _request(() async { - return await http.put(Uri.parse(url), headers: headers, body: body, encoding: encoding); + return await http.put(Uri.parse(url), + headers: headers, body: body, encoding: encoding); }); } static Future patch(String url, {Map? headers, dynamic body, Encoding? encoding}) async { return await _request(() async { - return await http.patch(Uri.parse(url), headers: headers, body: body, encoding: encoding); + return await http.patch(Uri.parse(url), + headers: headers, body: body, encoding: encoding); }); } - static Future delete(String url, {Map? headers}) async { + static Future delete(String url, + {Map? headers}) async { return await _request(() async { return await http.delete(Uri.parse(url), headers: headers); }); } - static Future head(String url, {Map? headers}) async { + static Future head(String url, + {Map? headers}) async { return await _request(() async { return await http.head(Uri.parse(url), headers: headers); }); @@ -85,7 +93,8 @@ class HttpResponse { else if (raw.statusCode >= 500 && raw.statusCode < 600) errorType = NetErrorType.timedOut; //400's server is denying our request, probably bad auth or malformed request - else if (raw.statusCode >= 400 && raw.statusCode < 500) errorType = NetErrorType.denied; + else if (raw.statusCode >= 400 && raw.statusCode < 500) + errorType = NetErrorType.denied; } // NOTE CE: This just crahes on construction diff --git a/flokk_src/lib/_internal/log.dart b/flokk_src/lib/_internal/log.dart index 5c15303..06cfdb5 100644 --- a/flokk_src/lib/_internal/log.dart +++ b/flokk_src/lib/_internal/log.dart @@ -24,7 +24,9 @@ class Log { } static String _formatLine(String value, bool writeTimestamp) { - String date = writeTimestamp ? "${DateFormat("EEE MMM d @ H:m:s").format(DateTime.now())}" : ""; + String date = writeTimestamp + ? "${DateFormat("EEE MMM d @ H:m:s").format(DateTime.now())}" + : ""; return "$date: $value \n"; } @@ -32,7 +34,9 @@ class Log { init().then((dynamic value) { print("[ERROR] $error"); if (writeToDisk) { - _errorFile.write(_formatLine("[ERROR] $value\n${stack?.toString()}", writeTimestamp), true); + _errorFile.write( + _formatLine("[ERROR] $value\n${stack?.toString()}", writeTimestamp), + true); } }); } diff --git a/flokk_src/lib/_internal/page_routes.dart b/flokk_src/lib/_internal/page_routes.dart index b9fed32..11c63f4 100644 --- a/flokk_src/lib/_internal/page_routes.dart +++ b/flokk_src/lib/_internal/page_routes.dart @@ -8,7 +8,8 @@ class PageRoutes { static const Curve kDefaultEaseFwd = Curves.easeOut; static const Curve kDefaultEaseReverse = Curves.easeOut; - static Route fade(PageBuilder pageBuilder, [double duration = kDefaultDuration]) { + static Route fade(PageBuilder pageBuilder, + [double duration = kDefaultDuration]) { return PageRouteBuilder( transitionDuration: Duration(milliseconds: (duration * 1000).round()), pageBuilder: (context, animation, secondaryAnimation) => pageBuilder(), @@ -18,17 +19,22 @@ class PageRoutes { ); } - static Route fadeThrough(PageBuilder pageBuilder, [double duration = kDefaultDuration]) { + static Route fadeThrough(PageBuilder pageBuilder, + [double duration = kDefaultDuration]) { return PageRouteBuilder( transitionDuration: Duration(milliseconds: (duration * 1000).round()), pageBuilder: (context, animation, secondaryAnimation) => pageBuilder(), transitionsBuilder: (context, animation, secondaryAnimation, child) { - return FadeThroughTransition(animation: animation, secondaryAnimation: secondaryAnimation, child: child); + return FadeThroughTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: child); }, ); } - static Route fadeScale(PageBuilder pageBuilder, [double duration = kDefaultDuration]) { + static Route fadeScale(PageBuilder pageBuilder, + [double duration = kDefaultDuration]) { return PageRouteBuilder( transitionDuration: Duration(milliseconds: (duration * 1000).round()), pageBuilder: (context, animation, secondaryAnimation) => pageBuilder(), @@ -39,7 +45,8 @@ class PageRoutes { } static Route sharedAxis(PageBuilder pageBuilder, - [SharedAxisTransitionType type = SharedAxisTransitionType.scaled, double duration = kDefaultDuration]) { + [SharedAxisTransitionType type = SharedAxisTransitionType.scaled, + double duration = kDefaultDuration]) { return PageRouteBuilder( transitionDuration: Duration(milliseconds: (duration * 1000).round()), pageBuilder: (context, animation, secondaryAnimation) => pageBuilder(), @@ -66,7 +73,8 @@ class PageRoutes { bool reverse = animation.status == AnimationStatus.reverse; return SlideTransition( position: Tween(begin: startOffset, end: Offset(0, 0)) - .animate(CurvedAnimation(parent: animation, curve: reverse ? easeReverse : easeFwd)), + .animate(CurvedAnimation( + parent: animation, curve: reverse ? easeReverse : easeFwd)), child: child, ); }, diff --git a/flokk_src/lib/_internal/pointer_blocker.dart b/flokk_src/lib/_internal/pointer_blocker.dart index 5d4aab0..6e73780 100644 --- a/flokk_src/lib/_internal/pointer_blocker.dart +++ b/flokk_src/lib/_internal/pointer_blocker.dart @@ -4,7 +4,8 @@ class MouseAndPointerBlocker extends StatelessWidget { final Widget? child; final bool isEnabled; - const MouseAndPointerBlocker({Key? key, this.child, this.isEnabled = false}) : super(key: key); + const MouseAndPointerBlocker({Key? key, this.child, this.isEnabled = false}) + : super(key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/_internal/universal_file/universal_file.dart b/flokk_src/lib/_internal/universal_file/universal_file.dart index 79daa91..1b8acc0 100644 --- a/flokk_src/lib/_internal/universal_file/universal_file.dart +++ b/flokk_src/lib/_internal/universal_file/universal_file.dart @@ -1,7 +1,9 @@ //If in web, this class will write a string to the prefs file, using filename as key //If on desktop or mobile, write to the appData folder -import 'universal_file_locator.dart' if (dart.library.html) 'web_file.dart' if (dart.library.io) 'io_file.dart'; +import 'universal_file_locator.dart' + if (dart.library.html) 'web_file.dart' + if (dart.library.io) 'io_file.dart'; abstract class UniversalFile { String fileName = ""; diff --git a/flokk_src/lib/_internal/universal_file/universal_file_locator.dart b/flokk_src/lib/_internal/universal_file/universal_file_locator.dart index dfa6270..79c1f84 100644 --- a/flokk_src/lib/_internal/universal_file/universal_file_locator.dart +++ b/flokk_src/lib/_internal/universal_file/universal_file_locator.dart @@ -1,4 +1,4 @@ import 'universal_file.dart'; -UniversalFile getPlatformFileWriter(String fileName) => - throw UnsupportedError('Cannot create a fileWriter for "$fileName" without the packages dart:html or dart:io'); +UniversalFile getPlatformFileWriter(String fileName) => throw UnsupportedError( + 'Cannot create a fileWriter for "$fileName" without the packages dart:html or dart:io'); diff --git a/flokk_src/lib/_internal/universal_file/web_file.dart b/flokk_src/lib/_internal/universal_file/web_file.dart index c4eec93..d963e92 100644 --- a/flokk_src/lib/_internal/universal_file/web_file.dart +++ b/flokk_src/lib/_internal/universal_file/web_file.dart @@ -14,8 +14,7 @@ class WebFileWriter implements UniversalFile { WebFileWriter(this.fileName); Future initPrefs() async { - if (_hasPrefs) - return; + if (_hasPrefs) return; _hasPrefs = true; prefs = await SharedPreferences.getInstance(); } @@ -24,8 +23,7 @@ class WebFileWriter implements UniversalFile { Future read() async { await initPrefs(); String? value = prefs.getString(fileName); - if (value == null) - throw Exception("$fileName not found"); + if (value == null) throw Exception("$fileName not found"); //print("Reading pref: $fileName = $value"); return value; } diff --git a/flokk_src/lib/_internal/universal_picker/desktop_picker.dart b/flokk_src/lib/_internal/universal_picker/desktop_picker.dart index dce0bc7..81fd578 100644 --- a/flokk_src/lib/_internal/universal_picker/desktop_picker.dart +++ b/flokk_src/lib/_internal/universal_picker/desktop_picker.dart @@ -41,4 +41,5 @@ class DesktopPicker implements UniversalPicker { } } -UniversalPicker getPlatformPicker({required String accept}) => DesktopPicker(accept: accept); +UniversalPicker getPlatformPicker({required String accept}) => + DesktopPicker(accept: accept); diff --git a/flokk_src/lib/_internal/universal_picker/universal_picker.dart b/flokk_src/lib/_internal/universal_picker/universal_picker.dart index c25edb5..312628c 100644 --- a/flokk_src/lib/_internal/universal_picker/universal_picker.dart +++ b/flokk_src/lib/_internal/universal_picker/universal_picker.dart @@ -17,5 +17,6 @@ abstract class UniversalPicker { void open(); - factory UniversalPicker({String accept = ""}) => getPlatformPicker(accept: accept); + factory UniversalPicker({String accept = ""}) => + getPlatformPicker(accept: accept); } diff --git a/flokk_src/lib/_internal/universal_picker/universal_picker_locator.dart b/flokk_src/lib/_internal/universal_picker/universal_picker_locator.dart index b746c36..ca6e8f2 100644 --- a/flokk_src/lib/_internal/universal_picker/universal_picker_locator.dart +++ b/flokk_src/lib/_internal/universal_picker/universal_picker_locator.dart @@ -1,4 +1,5 @@ import 'universal_picker.dart'; -UniversalPicker getPlatformPicker({ required String accept }) => - throw UnsupportedError('Cannot create a picker without the packages dart:html or whatever is used for desktop'); +UniversalPicker getPlatformPicker({required String accept}) => + throw UnsupportedError( + 'Cannot create a picker without the packages dart:html or whatever is used for desktop'); diff --git a/flokk_src/lib/_internal/universal_picker/web_picker.dart b/flokk_src/lib/_internal/universal_picker/web_picker.dart index a912e83..7a86500 100644 --- a/flokk_src/lib/_internal/universal_picker/web_picker.dart +++ b/flokk_src/lib/_internal/universal_picker/web_picker.dart @@ -47,10 +47,10 @@ class WebPicker implements UniversalPicker { void handleFileLoad(ProgressEvent e) { base64Data = reader.result.toString().split(",").last; - if (base64Data != null) - byteData = Base64Decoder().convert(base64Data!); + if (base64Data != null) byteData = Base64Decoder().convert(base64Data!); onChange?.call(base64Data ?? ""); } } -UniversalPicker getPlatformPicker({ required String accept }) => WebPicker(accept: accept); +UniversalPicker getPlatformPicker({required String accept}) => + WebPicker(accept: accept); diff --git a/flokk_src/lib/_internal/url_launcher/url_launcher.dart b/flokk_src/lib/_internal/url_launcher/url_launcher.dart index 52be195..26dfc47 100644 --- a/flokk_src/lib/_internal/url_launcher/url_launcher.dart +++ b/flokk_src/lib/_internal/url_launcher/url_launcher.dart @@ -19,7 +19,8 @@ class UrlLauncher { } static void openPhoneNumber(String value) { - value = RegExp(r"([\d+])").allMatches(value).map((m) => m.group(0)).join(""); + value = + RegExp(r"([\d+])").allMatches(value).map((m) => m.group(0)).join(""); open("https://hangouts.google.com/?action=chat&pn=%2B$value&"); } @@ -28,9 +29,11 @@ class UrlLauncher { open("mailto:$value"); } - static void openGoogleMaps(String value) => open("https://www.google.com/maps/search/${Uri.encodeFull(value)}/"); + static void openGoogleMaps(String value) => + open("https://www.google.com/maps/search/${Uri.encodeFull(value)}/"); static void openGitUser(String value) => open("https://$value/"); - static void openTwitterUser(String value) => open("https://twitter.com/${value.replaceAll("@", "")}/"); + static void openTwitterUser(String value) => + open("https://twitter.com/${value.replaceAll("@", "")}/"); } diff --git a/flokk_src/lib/_internal/url_launcher/url_launcher_locator.dart b/flokk_src/lib/_internal/url_launcher/url_launcher_locator.dart index 3b1000a..2aa4b68 100644 --- a/flokk_src/lib/_internal/url_launcher/url_launcher_locator.dart +++ b/flokk_src/lib/_internal/url_launcher/url_launcher_locator.dart @@ -1 +1,2 @@ -Future urlLauncherOpen(String url) => throw UnsupportedError('Unimplemented Url Opener'); +Future urlLauncherOpen(String url) => + throw UnsupportedError('Unimplemented Url Opener'); diff --git a/flokk_src/lib/_internal/utils/build_utils.dart b/flokk_src/lib/_internal/utils/build_utils.dart index 805183d..b6676f1 100644 --- a/flokk_src/lib/_internal/utils/build_utils.dart +++ b/flokk_src/lib/_internal/utils/build_utils.dart @@ -1,14 +1,13 @@ import 'package:flutter/material.dart'; class BuildUtils { - - static void getFutureSizeFromGlobalKey(GlobalKey key, Function(Size size) callback) { + static void getFutureSizeFromGlobalKey( + GlobalKey key, Function(Size size) callback) { Future.microtask(() { BuildContext? ctx = key.currentContext; if (ctx != null) { Size? size = getSizeFromContext(ctx); - if (size != null) - callback(size); + if (size != null) callback(size); } }); } @@ -18,10 +17,9 @@ class BuildUtils { return rb?.size; } - static Offset? getOffsetFromContext(BuildContext context, [Offset offset = Offset.zero]) { + static Offset? getOffsetFromContext(BuildContext context, + [Offset offset = Offset.zero]) { RenderBox? rb = context.findRenderObject() as RenderBox?; return rb?.localToGlobal(offset); } - - } diff --git a/flokk_src/lib/_internal/utils/color_utils.dart b/flokk_src/lib/_internal/utils/color_utils.dart index 6838dbf..02af0d6 100644 --- a/flokk_src/lib/_internal/utils/color_utils.dart +++ b/flokk_src/lib/_internal/utils/color_utils.dart @@ -8,14 +8,18 @@ class ColorUtils { return hslc.withLightness((hslc.lightness + amt).clamp(0.0, 1.0)).toColor(); } - static Color parseHex(String value) => Color(int.parse(value.substring(1, 7), radix: 16) + 0xFF000000); + static Color parseHex(String value) => + Color(int.parse(value.substring(1, 7), radix: 16) + 0xFF000000); static Color blend(Color dst, Color src, double opacity) { return Color.fromARGB( 255, - (dst.red.toDouble() * (1.0 - opacity) + src.red.toDouble() * opacity).toInt(), - (dst.green.toDouble() * (1.0 - opacity) + src.green.toDouble() * opacity).toInt(), - (dst.blue.toDouble() * (1.0 - opacity) + src.blue.toDouble() * opacity).toInt(), + (dst.red.toDouble() * (1.0 - opacity) + src.red.toDouble() * opacity) + .toInt(), + (dst.green.toDouble() * (1.0 - opacity) + src.green.toDouble() * opacity) + .toInt(), + (dst.blue.toDouble() * (1.0 - opacity) + src.blue.toDouble() * opacity) + .toInt(), ); } } diff --git a/flokk_src/lib/_internal/utils/picker.dart b/flokk_src/lib/_internal/utils/picker.dart index 6faeb94..acb0cbf 100644 --- a/flokk_src/lib/_internal/utils/picker.dart +++ b/flokk_src/lib/_internal/utils/picker.dart @@ -2,11 +2,13 @@ import 'package:file_selector/file_selector.dart'; import 'path.dart'; -Future pickImage({String confirmText = "", String initialPath = ""}) async { +Future pickImage( + {String confirmText = "", String initialPath = ""}) async { if (confirmText.isEmpty) confirmText = "Pick Image"; if (initialPath.isEmpty) initialPath = await PathUtil.homePath; - final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'jpeg', 'png']); + final typeGroup = + XTypeGroup(label: 'images', extensions: ['jpg', 'jpeg', 'png']); XFile? file = (await openFile( initialDirectory: initialPath, confirmButtonText: confirmText, diff --git a/flokk_src/lib/_internal/utils/string_utils.dart b/flokk_src/lib/_internal/utils/string_utils.dart index a5ae6cd..273ffae 100644 --- a/flokk_src/lib/_internal/utils/string_utils.dart +++ b/flokk_src/lib/_internal/utils/string_utils.dart @@ -12,18 +12,24 @@ class StringUtils { static bool isEmailValid(String value) { if (StringUtils.isEmpty(value)) return false; - return RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value); + return RegExp( + r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") + .hasMatch(value); } // Here it is! - static Size measure(String text, TextStyle style, {int maxLines: 1, TextDirection direction = TextDirection.ltr}) { - final TextPainter textPainter = - TextPainter(text: TextSpan(text: text, style: style), maxLines: maxLines, textDirection: direction) - ..layout(minWidth: 0, maxWidth: double.infinity); + static Size measure(String text, TextStyle style, + {int maxLines: 1, TextDirection direction = TextDirection.ltr}) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + maxLines: maxLines, + textDirection: direction) + ..layout(minWidth: 0, maxWidth: double.infinity); return textPainter.size; } - static double measureLongest(List items, TextStyle style, [maxItems = null]) { + static double measureLongest(List items, TextStyle style, + [maxItems = null]) { double l = 0; if (maxItems != null && maxItems < items.length) { items.length = maxItems; diff --git a/flokk_src/lib/_internal/utils/utils.dart b/flokk_src/lib/_internal/utils/utils.dart index 5bc4fb7..515c760 100644 --- a/flokk_src/lib/_internal/utils/utils.dart +++ b/flokk_src/lib/_internal/utils/utils.dart @@ -7,7 +7,8 @@ class Utils { SystemChannels.textInput.invokeMethod('TextInput.hide'); } - static bool get isMouseConnected => RendererBinding.instance?.mouseTracker.mouseIsConnected ?? false; + static bool get isMouseConnected => + RendererBinding.instance?.mouseTracker.mouseIsConnected ?? false; static void unFocus() { primaryFocus?.unfocus(); @@ -16,6 +17,7 @@ class Utils { static void benchmark(String name, void Function() test) { int ms = DateTime.now().millisecondsSinceEpoch; test(); - print("Benchmark: $name == ${DateTime.now().millisecondsSinceEpoch - ms}ms"); + print( + "Benchmark: $name == ${DateTime.now().millisecondsSinceEpoch - ms}ms"); } } diff --git a/flokk_src/lib/commands/abstract_command.dart b/flokk_src/lib/commands/abstract_command.dart index f15fdb0..01e05ca 100644 --- a/flokk_src/lib/commands/abstract_command.dart +++ b/flokk_src/lib/commands/abstract_command.dart @@ -67,12 +67,14 @@ mixin AuthorizedServiceCommandMixin on AbstractCommand { bool ignoreErrors = false; /// Runs a service that refreshes Auth if needed, and checks for errors on completion - Future> executeAuthServiceCmd(Future> Function() cmd) async { + Future> executeAuthServiceCmd( + Future> Function() cmd) async { /// Bail early if we're offline if (!appModel.isOnline) { Dialogs.show(OkCancelDialog( title: "No Connection", - message: "It appears your device is offline. Please check your connection and try again.", + message: + "It appears your device is offline. Please check your connection and try again.", onOkPressed: () => rootNav?.pop(), )); } diff --git a/flokk_src/lib/commands/bootstrap_command.dart b/flokk_src/lib/commands/bootstrap_command.dart index 3582b40..7492744 100644 --- a/flokk_src/lib/commands/bootstrap_command.dart +++ b/flokk_src/lib/commands/bootstrap_command.dart @@ -74,7 +74,8 @@ class BootstrapCommand extends AbstractCommand { /// //////////////////////////////////////////////////////////////// /// Debug: Inject authModel in web dev builds for quicker local testing /// TODO: Remove before release - bool sideStepLoginFlow = (kDebugMode || kForceWebLogin) && (UniversalPlatform.isWeb || UniversalPlatform.isAndroid); + bool sideStepLoginFlow = (kDebugMode || kForceWebLogin) && + (UniversalPlatform.isWeb || UniversalPlatform.isAndroid); if (sideStepLoginFlow) { // Force login on the web by injecting a known refresh token, which we can use to fetch a valid authKey authModel.googleRefreshToken = @@ -92,7 +93,8 @@ class BootstrapCommand extends AbstractCommand { bool authSuccess; if (UniversalPlatform.isWeb) { // On web, perform a silentSignIn to refresh the OAuth token - authSuccess = await WebSignInCommand(context).execute(silentSignIn: true); + authSuccess = + await WebSignInCommand(context).execute(silentSignIn: true); } else { // On desktop, refresh the authToken manually authSuccess = await RefreshAuthTokensCommand(context).execute(); @@ -103,7 +105,9 @@ class BootstrapCommand extends AbstractCommand { } } // Load contacts - ServiceResult contactsResult = await (RefreshContactsCommand(context)..ignoreErrors = true).execute(); + ServiceResult contactsResult = await (RefreshContactsCommand(context) + ..ignoreErrors = true) + .execute(); if (contactsResult.success) { await RefreshSocialCommand(context).execute(contactsModel.allContacts); } diff --git a/flokk_src/lib/commands/check_connection_command.dart b/flokk_src/lib/commands/check_connection_command.dart index 172e403..6c47680 100644 --- a/flokk_src/lib/commands/check_connection_command.dart +++ b/flokk_src/lib/commands/check_connection_command.dart @@ -4,7 +4,8 @@ import 'package:flokk/commands/abstract_command.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:universal_platform/universal_platform.dart'; -class CheckConnectionCommand extends AbstractCommand with CancelableCommandMixin { +class CheckConnectionCommand extends AbstractCommand + with CancelableCommandMixin { CheckConnectionCommand(BuildContext context) : super(context); /// Checks if we can connect to the internet. diff --git a/flokk_src/lib/commands/contacts/delete_contact_command.dart b/flokk_src/lib/commands/contacts/delete_contact_command.dart index 045d532..a062376 100644 --- a/flokk_src/lib/commands/contacts/delete_contact_command.dart +++ b/flokk_src/lib/commands/contacts/delete_contact_command.dart @@ -8,13 +8,19 @@ import 'package:flokk/services/service_result.dart'; import 'package:flokk/styled_components/styled_dialogs.dart'; import 'package:flutter/cupertino.dart'; -class DeleteContactCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class DeleteContactCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { DeleteContactCommand(BuildContext c) : super(c); - Future execute(List contacts, {VoidCallback? onDeleteConfirmed}) async { - if (contacts == null || contacts.isEmpty || AppModel.forceIgnoreGoogleApiCalls) return false; + Future execute(List contacts, + {VoidCallback? onDeleteConfirmed}) async { + if (contacts == null || + contacts.isEmpty || + AppModel.forceIgnoreGoogleApiCalls) return false; Log.p("[DeleteContactCommand]"); - String txt = contacts.length > 1 ? "these ${contacts.length} contacts" : "this contact"; + String txt = contacts.length > 1 + ? "these ${contacts.length} contacts" + : "this contact"; bool doDelete = await Dialogs.show( OkCancelDialog( message: "Are you sure you want to delete $txt?", @@ -35,8 +41,9 @@ class DeleteContactCommand extends AbstractCommand with AuthorizedServiceCommand } /// Create a list of futures - List> futures = - contacts.map((c) => service.delete(authModel.googleAccessToken, c)).toList(); + List> futures = contacts + .map((c) => service.delete(authModel.googleAccessToken, c)) + .toList(); // Dispatch them all at once List results = await Future.wait(futures); //Request succeeded? diff --git a/flokk_src/lib/commands/contacts/delete_pic_command.dart b/flokk_src/lib/commands/contacts/delete_pic_command.dart index c61b3ea..8478969 100644 --- a/flokk_src/lib/commands/contacts/delete_pic_command.dart +++ b/flokk_src/lib/commands/contacts/delete_pic_command.dart @@ -7,11 +7,13 @@ import 'package:flokk/services/service_result.dart'; import 'package:flokk/styled_components/styled_dialogs.dart'; import 'package:flutter/src/widgets/framework.dart'; -class DeletePicCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class DeletePicCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { DeletePicCommand(BuildContext c) : super(c); Future execute(ContactData contact) async { - if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) return false; + if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) + return false; Log.p("[DeletePicCommand]"); bool doDelete = await Dialogs.show( @@ -29,7 +31,8 @@ class DeletePicCommand extends AbstractCommand with AuthorizedServiceCommandMixi //Update local data optimistically ServiceResult result = await executeAuthServiceCmd(() async { //Update remove database - ServiceResult result = await googleRestService.contacts.deletePic(authModel.googleAccessToken, contact); + ServiceResult result = await googleRestService.contacts + .deletePic(authModel.googleAccessToken, contact); //Request succeeded? if (result.success) { RefreshContactsCommand(context).execute(); diff --git a/flokk_src/lib/commands/contacts/refresh_contacts_command.dart b/flokk_src/lib/commands/contacts/refresh_contacts_command.dart index bd43f75..30a46cc 100644 --- a/flokk_src/lib/commands/contacts/refresh_contacts_command.dart +++ b/flokk_src/lib/commands/contacts/refresh_contacts_command.dart @@ -6,20 +6,22 @@ import 'package:flokk/services/google_rest/google_rest_contacts_service.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class RefreshContactsCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class RefreshContactsCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { RefreshContactsCommand(BuildContext c) : super(c); Future execute({bool skipGroups = false}) async { Log.p("[RefreshContactsCommand]"); - ServiceResult result = await executeAuthServiceCmd(() async { + ServiceResult result = + await executeAuthServiceCmd(() async { // Check if we have a sync token... String syncToken = authModel.googleSyncToken ?? ""; if (contactsModel.allContacts.isEmpty) { syncToken = ""; } - ServiceResult result = - await googleRestService.contacts.getAll(authModel.googleAccessToken, syncToken); + ServiceResult result = await googleRestService.contacts + .getAll(authModel.googleAccessToken, syncToken); // Now do we have a sync token? syncToken = result.content?.syncToken ?? ""; List contacts = result.content?.contacts ?? []; diff --git a/flokk_src/lib/commands/contacts/toggle_favorite_command.dart b/flokk_src/lib/commands/contacts/toggle_favorite_command.dart index a72fee2..3409653 100644 --- a/flokk_src/lib/commands/contacts/toggle_favorite_command.dart +++ b/flokk_src/lib/commands/contacts/toggle_favorite_command.dart @@ -7,7 +7,8 @@ import 'package:flokk/services/google_rest/google_rest_service.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class ToggleFavoriteCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class ToggleFavoriteCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { ToggleFavoriteCommand(BuildContext c) : super(c); Future execute(ContactData contact) async { @@ -26,10 +27,13 @@ class ToggleFavoriteCommand extends AbstractCommand with AuthorizedServiceComman if (contact.isStarred) { //add to favorites group - result = await googleRestService.groups.modify(authModel.googleAccessToken, group, addContacts: [contact]); + result = await googleRestService.groups + .modify(authModel.googleAccessToken, group, addContacts: [contact]); } else { //remove from favorites group - result = await googleRestService.groups.modify(authModel.googleAccessToken, group, removeContacts: [contact]); + result = await googleRestService.groups.modify( + authModel.googleAccessToken, group, + removeContacts: [contact]); } // Dispatch background refresh command to make sure we're in sync RefreshContactGroupsCommand(context).execute(onlyStarred: true); diff --git a/flokk_src/lib/commands/contacts/update_contact_command.dart b/flokk_src/lib/commands/contacts/update_contact_command.dart index 09c346f..c418858 100644 --- a/flokk_src/lib/commands/contacts/update_contact_command.dart +++ b/flokk_src/lib/commands/contacts/update_contact_command.dart @@ -7,18 +7,22 @@ import 'package:flokk/models/app_model.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class UpdateContactCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class UpdateContactCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { UpdateContactCommand(BuildContext c) : super(c); - Future execute(ContactData contact, {bool updateSocial: false, bool tryAgainOnError = true}) async { - if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) return ContactData(); + Future execute(ContactData contact, + {bool updateSocial: false, bool tryAgainOnError = true}) async { + if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) + return ContactData(); Log.p("[UpdateContactCommand]"); ServiceResult result = await executeAuthServiceCmd(() async { ServiceResult result; if (contact.isNew) { /// Update remote database - result = await googleRestService.contacts.create(authModel.googleAccessToken, contact); + result = await googleRestService.contacts + .create(authModel.googleAccessToken, contact); if (result.success) { result.content!.isRecentlyAdded = true; contactsModel.addContact(result.content!); @@ -48,7 +52,8 @@ class UpdateContactCommand extends AbstractCommand with AuthorizedServiceCommand if (updateSocial) RefreshSocialCommand(context).execute([contact]); /// Update remote database - result = await googleRestService.contacts.set(authModel.googleAccessToken, contact); + result = await googleRestService.contacts + .set(authModel.googleAccessToken, contact); /// Since we get back the updated object, we can inject it straight into the model to keep us in sync print("Success: ${result.success}, etag=${contact.etag}"); diff --git a/flokk_src/lib/commands/contacts/update_pic_command.dart b/flokk_src/lib/commands/contacts/update_pic_command.dart index f126808..ff22c1a 100644 --- a/flokk_src/lib/commands/contacts/update_pic_command.dart +++ b/flokk_src/lib/commands/contacts/update_pic_command.dart @@ -6,16 +6,18 @@ import 'package:flokk/models/app_model.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class UpdatePicCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class UpdatePicCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { UpdatePicCommand(BuildContext c) : super(c); Future execute(ContactData contact, String base64Pic) async { - if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) return false; + if (contact == ContactData() || AppModel.forceIgnoreGoogleApiCalls) + return false; Log.p("[UpdatePicCommand]"); ServiceResult result = await executeAuthServiceCmd(() async { - ServiceResult result = - await googleRestService.contacts.updatePic(authModel.googleAccessToken, contact, base64Pic); + ServiceResult result = await googleRestService.contacts + .updatePic(authModel.googleAccessToken, contact, base64Pic); if (result.success) { contact.profilePic = result.content.profilePic; contact.isDefaultPic = result.content.isDefaultPic; diff --git a/flokk_src/lib/commands/dialogs/show_discard_warning_command.dart b/flokk_src/lib/commands/dialogs/show_discard_warning_command.dart index e267fe3..0a77bc2 100644 --- a/flokk_src/lib/commands/dialogs/show_discard_warning_command.dart +++ b/flokk_src/lib/commands/dialogs/show_discard_warning_command.dart @@ -14,7 +14,8 @@ class ShowDiscardWarningCommand extends AbstractCommand { return await Dialogs.show(OkCancelDialog( okLabel: "DISCARD", title: "UNSAVED CHANGES FOR ${isNew ? "NEW " : ""}CONTACT", - message: "You have unsaved changes which will be lost if you navigate away.\n" + message: + "You have unsaved changes which will be lost if you navigate away.\n" "Are you sure you wish to discard these changes?", onOkPressed: () => rootNav?.pop(true), onCancelPressed: () => rootNav?.pop(false), diff --git a/flokk_src/lib/commands/dialogs/show_service_error_command.dart b/flokk_src/lib/commands/dialogs/show_service_error_command.dart index a040de5..08e98fb 100644 --- a/flokk_src/lib/commands/dialogs/show_service_error_command.dart +++ b/flokk_src/lib/commands/dialogs/show_service_error_command.dart @@ -14,7 +14,8 @@ class ShowServiceErrorCommand extends AbstractCommand { static bool isShowingError = false; - Future execute(HttpResponse response, {String customMessage = ""}) async { + Future execute(HttpResponse response, + {String customMessage = ""}) async { //If response has no errors, return false to indicate no error was shown if (response.success) return false; Log.p("[ShowServiceErrorCommand]"); @@ -37,7 +38,8 @@ class ShowServiceErrorCommand extends AbstractCommand { if (json?.containsKey("message") ?? false) { msg = json!["message"]; } else { - msg = "Unable to connect to online services: Internal Server Error (${response.statusCode})"; + msg = + "Unable to connect to online services: Internal Server Error (${response.statusCode})"; } } } @@ -54,7 +56,8 @@ class ShowServiceErrorCommand extends AbstractCommand { } // No Connection else if (response.errorType == NetErrorType.disconnected) { - msg = "Unable to connect to the internet, please check your connection."; + msg = + "Unable to connect to the internet, please check your connection."; //Run an immediate connection check, it's likely that we've lost connection but we're not sure. await CheckConnectionCommand(context).execute(false); } diff --git a/flokk_src/lib/commands/groups/add_label_to_contact_command.dart b/flokk_src/lib/commands/groups/add_label_to_contact_command.dart index e04cfe8..9635c01 100644 --- a/flokk_src/lib/commands/groups/add_label_to_contact_command.dart +++ b/flokk_src/lib/commands/groups/add_label_to_contact_command.dart @@ -8,10 +8,12 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/cupertino.dart'; -class AddLabelToContactCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class AddLabelToContactCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { AddLabelToContactCommand(BuildContext c) : super(c); - Future> execute(List contacts, {required GroupData existingGroup, String newLabel = ""}) async { + Future> execute(List contacts, + {required GroupData existingGroup, String newLabel = ""}) async { Log.p("[AddLabelToContactCommand]"); await executeAuthServiceCmd(() async { GroupData group = GroupData(); @@ -24,7 +26,8 @@ class AddLabelToContactCommand extends AbstractCommand with AuthorizedServiceCom } ServiceResult result = ServiceResult(null, HttpResponse.empty()); if (group != GroupData()) { - result = await googleRestService.groups.modify(authModel.googleAccessToken, group, addContacts: contacts); + result = await googleRestService.groups + .modify(authModel.googleAccessToken, group, addContacts: contacts); } return result; }); diff --git a/flokk_src/lib/commands/groups/create_label_command.dart b/flokk_src/lib/commands/groups/create_label_command.dart index ca3d85e..cf69fb1 100644 --- a/flokk_src/lib/commands/groups/create_label_command.dart +++ b/flokk_src/lib/commands/groups/create_label_command.dart @@ -4,14 +4,16 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class CreateLabelCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class CreateLabelCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { CreateLabelCommand(BuildContext c) : super(c); Future execute(String labelName) async { Log.p("[CreateLabelCommand]"); GroupData newGroup = GroupData()..name = labelName; ServiceResult result = await executeAuthServiceCmd(() async { - ServiceResult result = await googleRestService.groups.create(authModel.googleAccessToken, newGroup); + ServiceResult result = await googleRestService.groups + .create(authModel.googleAccessToken, newGroup); newGroup = result.content ?? GroupData(); if (result.success) { diff --git a/flokk_src/lib/commands/groups/delete_label_command.dart b/flokk_src/lib/commands/groups/delete_label_command.dart index da427b9..709d559 100644 --- a/flokk_src/lib/commands/groups/delete_label_command.dart +++ b/flokk_src/lib/commands/groups/delete_label_command.dart @@ -5,14 +5,16 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/cupertino.dart'; -class DeleteLabelCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class DeleteLabelCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { DeleteLabelCommand(BuildContext c) : super(c); Future execute(GroupData group) async { if (group == GroupData()) return false; Log.p("[DeleteLabelCommand]"); ServiceResult result = await executeAuthServiceCmd(() async { - ServiceResult result = await googleRestService.groups.delete(authModel.googleAccessToken, group); + ServiceResult result = await googleRestService.groups + .delete(authModel.googleAccessToken, group); if (result.success) { //refresh the groups to ensure labels synced await RefreshContactGroupsCommand(context).execute(forceUpdate: true); diff --git a/flokk_src/lib/commands/groups/refresh_contact_groups_command.dart b/flokk_src/lib/commands/groups/refresh_contact_groups_command.dart index 683126d..129ceba 100644 --- a/flokk_src/lib/commands/groups/refresh_contact_groups_command.dart +++ b/flokk_src/lib/commands/groups/refresh_contact_groups_command.dart @@ -9,23 +9,29 @@ import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:tuple/tuple.dart'; -class RefreshContactGroupsCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class RefreshContactGroupsCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { RefreshContactGroupsCommand(BuildContext c) : super(c); - Future> execute({bool onlyStarred = false, bool forceUpdate = false}) async { + Future> execute( + {bool onlyStarred = false, bool forceUpdate = false}) async { Log.p("[RefreshContactGroupsCommand]"); - if (contactsModel.canRefreshContactGroups || forceUpdate || AppModel.ignoreCooldowns) { + if (contactsModel.canRefreshContactGroups || + forceUpdate || + AppModel.ignoreCooldowns) { contactsModel.lastUpdatedGroups = DateTime.now(); await executeAuthServiceCmd(() async { GoogleRestContactGroupsService groupsApi = googleRestService.groups; - ServiceResult result = ServiceResult(null, HttpResponse.empty()); + ServiceResult result = + ServiceResult(null, HttpResponse.empty()); if (onlyStarred) { - result = - await groupsApi.getById(authModel.googleAccessToken, GoogleRestService.kStarredGroupId); + result = await groupsApi.getById( + authModel.googleAccessToken, GoogleRestService.kStarredGroupId); if (result.success) { - GroupData starred = contactsModel.getGroupById(GoogleRestService.kStarredGroupId); + GroupData starred = + contactsModel.getGroupById(GoogleRestService.kStarredGroupId); if (starred != GroupData()) { starred.members = result.content?.members ?? []; } else { @@ -33,13 +39,15 @@ class RefreshContactGroupsCommand extends AbstractCommand with AuthorizedService } } } else { - ServiceResult, String>> result = await groupsApi.get(authModel.googleAccessToken); + ServiceResult, String>> result = + await groupsApi.get(authModel.googleAccessToken); List groups = result.content?.item1 ?? []; String nextPageToken = result.content?.item2 ?? ""; while (nextPageToken != "" && result.success) { ServiceResult, String>> result = - await groupsApi.get(authModel.googleAccessToken, nextPageToken: nextPageToken); + await groupsApi.get(authModel.googleAccessToken, + nextPageToken: nextPageToken); groups.addAll(result.content?.item1 ?? []); nextPageToken = result.content?.item2 ?? ""; } @@ -47,9 +55,10 @@ class RefreshContactGroupsCommand extends AbstractCommand with AuthorizedService if (groups.isNotEmpty && result.success) { //Need to fetch each individual group to get members list for (int i = 0; i < groups.length; i++) { - if (groups[i].memberCount > 0 || groups[i].id == GoogleRestService.kStarredGroupId) { - ServiceResult groupResult = - await groupsApi.getById(authModel.googleAccessToken, groups[i].id); + if (groups[i].memberCount > 0 || + groups[i].id == GoogleRestService.kStarredGroupId) { + ServiceResult groupResult = await groupsApi.getById( + authModel.googleAccessToken, groups[i].id); if (groupResult.success) { groups[i].members = groupResult.content?.members ?? []; } diff --git a/flokk_src/lib/commands/groups/remove_label_from_contact_command.dart b/flokk_src/lib/commands/groups/remove_label_from_contact_command.dart index 054cc2b..6a0bebc 100644 --- a/flokk_src/lib/commands/groups/remove_label_from_contact_command.dart +++ b/flokk_src/lib/commands/groups/remove_label_from_contact_command.dart @@ -6,14 +6,17 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/cupertino.dart'; -class RemoveLabelFromContactCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class RemoveLabelFromContactCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { RemoveLabelFromContactCommand(BuildContext c) : super(c); Future execute(ContactData contact, GroupData group) async { Log.p("[RemoveLabelFromContactCommand]"); await executeAuthServiceCmd(() async { - ServiceResult result = await googleRestService.groups.modify(authModel.googleAccessToken, group, removeContacts: [contact]); + ServiceResult result = await googleRestService.groups.modify( + authModel.googleAccessToken, group, + removeContacts: [contact]); if (result.success) { //refresh the groups to ensure labels synced await RefreshContactGroupsCommand(context).execute(forceUpdate: true); diff --git a/flokk_src/lib/commands/groups/rename_label_command.dart b/flokk_src/lib/commands/groups/rename_label_command.dart index b1d130d..20d7063 100644 --- a/flokk_src/lib/commands/groups/rename_label_command.dart +++ b/flokk_src/lib/commands/groups/rename_label_command.dart @@ -4,14 +4,16 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/src/widgets/framework.dart'; -class RenameLabelCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class RenameLabelCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { RenameLabelCommand(BuildContext c) : super(c); Future execute(GroupData group) async { if (group == GroupData()) return group; Log.p("[RenameLabelCommand]"); ServiceResult result = await executeAuthServiceCmd(() async { - ServiceResult result = await googleRestService.groups.set(authModel.googleAccessToken, group); + ServiceResult result = await googleRestService.groups + .set(authModel.googleAccessToken, group); if (result.success) { contactsModel.swapGroupById(result.content!); } diff --git a/flokk_src/lib/commands/groups/update_contact_labels_command.dart b/flokk_src/lib/commands/groups/update_contact_labels_command.dart index 7ddd377..5933839 100644 --- a/flokk_src/lib/commands/groups/update_contact_labels_command.dart +++ b/flokk_src/lib/commands/groups/update_contact_labels_command.dart @@ -6,31 +6,39 @@ import 'package:flokk/data/group_data.dart'; import 'package:flokk/services/service_result.dart'; import 'package:flutter/cupertino.dart'; -class UpdateContactLabelsCommand extends AbstractCommand with AuthorizedServiceCommandMixin { +class UpdateContactLabelsCommand extends AbstractCommand + with AuthorizedServiceCommandMixin { UpdateContactLabelsCommand(BuildContext c) : super(c); Future execute(ContactData contact) async { Log.p("[UpdateContactLabelsCommand]"); await executeAuthServiceCmd(() async { //Get the existing labels for contact - List existingGroups = contactsModel.getContactById(contact.id)?.groupList ?? []; + List existingGroups = + contactsModel.getContactById(contact.id)?.groupList ?? []; //The updated labels for contact List updatedGroups = contact.groupList ?? []; - List removeFrom = existingGroups.where((x) => !updatedGroups.any((y) => y.id == x.id)).toList(); - List addTo = updatedGroups.where((x) => !existingGroups.any((y) => y.id == x.id)).toList(); + List removeFrom = existingGroups + .where((x) => !updatedGroups.any((y) => y.id == x.id)) + .toList(); + List addTo = updatedGroups + .where((x) => !existingGroups.any((y) => y.id == x.id)) + .toList(); ServiceResult result = ServiceResult(null, HttpResponse.empty()); //Remove contact from groups they are no longer in for (var n in removeFrom) { - result = await googleRestService.groups.modify(authModel.googleAccessToken, n, removeContacts: [contact]); + result = await googleRestService.groups + .modify(authModel.googleAccessToken, n, removeContacts: [contact]); print("Removed: ${n.name} from ${contact.nameFull}"); } //Add contact to groups they are not in for (var n in addTo) { - result = await googleRestService.groups.modify(authModel.googleAccessToken, n, addContacts: [contact]); + result = await googleRestService.groups + .modify(authModel.googleAccessToken, n, addContacts: [contact]); print("Added: ${n.name} to ${contact.nameFull}"); } return result; diff --git a/flokk_src/lib/commands/logout_command.dart b/flokk_src/lib/commands/logout_command.dart index 09a6ed9..2036843 100644 --- a/flokk_src/lib/commands/logout_command.dart +++ b/flokk_src/lib/commands/logout_command.dart @@ -34,6 +34,7 @@ class LogoutCommand extends AbstractCommand { appModel.reset(false); //Show login page - rootNav?.pushReplacement(PageRoutes.fade(() => WelcomePage(initialPanelOpen: true))); + rootNav?.pushReplacement( + PageRoutes.fade(() => WelcomePage(initialPanelOpen: true))); } } diff --git a/flokk_src/lib/commands/refresh_auth_tokens_command.dart b/flokk_src/lib/commands/refresh_auth_tokens_command.dart index e2d2964..be4e4dc 100644 --- a/flokk_src/lib/commands/refresh_auth_tokens_command.dart +++ b/flokk_src/lib/commands/refresh_auth_tokens_command.dart @@ -9,14 +9,16 @@ class RefreshAuthTokensCommand extends AbstractCommand { RefreshAuthTokensCommand(BuildContext context) : super(context); Future execute({bool onlyIfExpired = false}) async { - Log.p("[RefreshAuthTokensCommand] Refreshing with token: ${authModel.googleRefreshToken}"); + Log.p( + "[RefreshAuthTokensCommand] Refreshing with token: ${authModel.googleRefreshToken}"); if (StringUtils.isEmpty(authModel.googleRefreshToken)) return true; //Don't bother calling refresh if it's already authenticated if (onlyIfExpired && !authModel.isExpired) return true; //Query server, see if we can get a new auth token - ServiceResult result = await googleRestService.auth.refresh(authModel.googleRefreshToken ?? ""); + ServiceResult result = await googleRestService.auth + .refresh(authModel.googleRefreshToken ?? ""); //If the request succeeded, inject the model with the latest authToken and write to disk if (result.success) { authModel.googleAccessToken = result.content?.accessToken ?? ""; diff --git a/flokk_src/lib/commands/social/refresh_github_command.dart b/flokk_src/lib/commands/social/refresh_github_command.dart index 291e3c8..7a02e9f 100644 --- a/flokk_src/lib/commands/social/refresh_github_command.dart +++ b/flokk_src/lib/commands/social/refresh_github_command.dart @@ -13,21 +13,25 @@ class RefreshGithubCommand extends AbstractCommand { Future execute(String githubUsername) async { Log.p("[RefreshGithubCommand]"); - if (contactsModel.canRefreshGitEventsFor(githubUsername) || AppModel.ignoreCooldowns) { + if (contactsModel.canRefreshGitEventsFor(githubUsername) || + AppModel.ignoreCooldowns) { githubModel.isLoading = true; - ServiceResult eventResult = await gitService.getUserEvents(githubUsername); + ServiceResult eventResult = + await gitService.getUserEvents(githubUsername); contactsModel.updateSocialTimestamps(gitUsername: githubUsername); //set "hasValidGit" flag on contact, depending on success of call - contactsModel.updateContactDataGithubValidity(githubUsername, eventResult.success); + contactsModel.updateContactDataGithubValidity( + githubUsername, eventResult.success); //Suppress error dialogs if the git username is not found. Already updated the ContactData.hasValidGit flag above final int statusCode = eventResult.response.statusCode; switch (statusCode) { case 403: //rate limit (https://developer.github.com/v3/#rate-limiting) - ShowServiceErrorCommand(context) - .execute(eventResult.response, customMessage: "GitHub rate limit exceeded. Please try again later."); + ShowServiceErrorCommand(context).execute(eventResult.response, + customMessage: + "GitHub rate limit exceeded. Please try again later."); break; case 404: //likely invalid git username, don't bother showing error dialog. break; @@ -45,7 +49,8 @@ class RefreshGithubCommand extends AbstractCommand { String fullName = n.event.repo?.name ?? ""; if (githubModel.repoIsStale(fullName)) { - ServiceResult repoResult = await gitService.getRepo(fullName); + ServiceResult repoResult = + await gitService.getRepo(fullName); if (repoResult.success == true) { GitRepo repo = repoResult.content!; githubModel.addRepo(repo); diff --git a/flokk_src/lib/commands/social/refresh_social_command.dart b/flokk_src/lib/commands/social/refresh_social_command.dart index 57712d4..c6be3be 100644 --- a/flokk_src/lib/commands/social/refresh_social_command.dart +++ b/flokk_src/lib/commands/social/refresh_social_command.dart @@ -15,15 +15,23 @@ class RefreshSocialCommand extends AbstractCommand { return; } - List githubHandles = - contacts.where((x) => !StringUtils.isEmpty(x.gitUsername)).map((x) => x.gitUsername).toList(); - List twitterHandles = - contacts.where((x) => !StringUtils.isEmpty(x.twitterHandle)).map((x) => x.twitterHandle).toList(); + List githubHandles = contacts + .where((x) => !StringUtils.isEmpty(x.gitUsername)) + .map((x) => x.gitUsername) + .toList(); + List twitterHandles = contacts + .where((x) => !StringUtils.isEmpty(x.twitterHandle)) + .map((x) => x.twitterHandle) + .toList(); - List> gitFutures = githubHandles.map((x) => RefreshGithubCommand(context).execute(x)).toList(); + List> gitFutures = githubHandles + .map((x) => RefreshGithubCommand(context).execute(x)) + .toList(); await Future.wait(gitFutures); - List> twitterFutures = twitterHandles.map((x) => RefreshTwitterCommand(context).execute(x)).toList(); + List> twitterFutures = twitterHandles + .map((x) => RefreshTwitterCommand(context).execute(x)) + .toList(); await Future.wait(twitterFutures); } } diff --git a/flokk_src/lib/commands/social/refresh_twitter_command.dart b/flokk_src/lib/commands/social/refresh_twitter_command.dart index c6ce4c9..a6e2b4b 100644 --- a/flokk_src/lib/commands/social/refresh_twitter_command.dart +++ b/flokk_src/lib/commands/social/refresh_twitter_command.dart @@ -13,24 +13,28 @@ class RefreshTwitterCommand extends AbstractCommand { Future execute(String twitterHandle) async { Log.p("[RefreshTwitterCommand]"); - if (contactsModel.canRefreshTweetsFor(twitterHandle) || AppModel.ignoreCooldowns) { + if (contactsModel.canRefreshTweetsFor(twitterHandle) || + AppModel.ignoreCooldowns) { if (!twitterModel.isAuthenticated) { await AuthenticateTwitterCommand(context).execute(); } twitterModel.isLoading = true; - ServiceResult result = await twitterService.getTweets(twitterModel.twitterAccessToken, twitterHandle); + ServiceResult result = await twitterService.getTweets( + twitterModel.twitterAccessToken, twitterHandle); contactsModel.updateSocialTimestamps(twitterHandle: twitterHandle); //set "hasValidTwitter" flag on contact, depending on success of call - contactsModel.updateContactDataTwitterValidity(twitterHandle, result.success); + contactsModel.updateContactDataTwitterValidity( + twitterHandle, result.success); //Suppress error dialogs if the twitter handle is not found. Already updated the ContactData.hasValidTwitter flag above final int statusCode = result.response.statusCode; switch (statusCode) { case 429: //rate limit (https://developer.twitter.com/en/docs/basics/rate-limiting) - ShowServiceErrorCommand(context) - .execute(result.response, customMessage: "Twitter rate limit exceeded. Please try again later."); + ShowServiceErrorCommand(context).execute(result.response, + customMessage: + "Twitter rate limit exceeded. Please try again later."); break; case 404: //likely invalid twitter username, don't bother showing error dialog. break; @@ -43,7 +47,10 @@ class RefreshTwitterCommand extends AbstractCommand { twitterModel.addTweets(twitterHandle, tweets); twitterModel.isLoading = false; twitterModel.scheduleSave(); - int newTweets = contactsModel.getSocialContactByTwitter(twitterHandle).newTweets.length; + int newTweets = contactsModel + .getSocialContactByTwitter(twitterHandle) + .newTweets + .length; print("New Tweets = $newTweets"); } } diff --git a/flokk_src/lib/commands/social/test_repeat_command.dart b/flokk_src/lib/commands/social/test_repeat_command.dart index 0f66cfc..9a329f6 100644 --- a/flokk_src/lib/commands/social/test_repeat_command.dart +++ b/flokk_src/lib/commands/social/test_repeat_command.dart @@ -13,7 +13,9 @@ class TestRepeatCommand extends AbstractCommand { } Future> execute( - {bool poll = false, Duration pollInterval = const Duration(seconds: 5), bool calledBySelf = false}) async { + {bool poll = false, + Duration pollInterval = const Duration(seconds: 5), + bool calledBySelf = false}) async { //reset the _isCancelled flag if poll is true and executed by self, allows proper restart of polling if (poll && !calledBySelf) { _isCancelled = false; diff --git a/flokk_src/lib/commands/web_sign_in_command.dart b/flokk_src/lib/commands/web_sign_in_command.dart index 5cf0950..6442012 100644 --- a/flokk_src/lib/commands/web_sign_in_command.dart +++ b/flokk_src/lib/commands/web_sign_in_command.dart @@ -15,10 +15,10 @@ class WebSignInCommand extends AbstractCommand { scopes: ['https://www.googleapis.com/auth/contacts'], ); - GoogleSignInAccount? account = silentSignIn ? await gs.signInSilently() : await gs.signIn(); + GoogleSignInAccount? account = + silentSignIn ? await gs.signInSilently() : await gs.signIn(); GoogleSignInAuthentication? auth; - if (account != null) - auth = await account.authentication; + if (account != null) auth = await account.authentication; if (auth != null) { Log.p("[WebSignInCommand] Success"); diff --git a/flokk_src/lib/data/contact_data.dart b/flokk_src/lib/data/contact_data.dart index d472730..33dc6b3 100644 --- a/flokk_src/lib/data/contact_data.dart +++ b/flokk_src/lib/data/contact_data.dart @@ -116,9 +116,11 @@ class ContactData { ContactData(); - factory ContactData.fromJson(Map json) => _$ContactDataFromJson(json); + factory ContactData.fromJson(Map json) => + _$ContactDataFromJson(json); - bool get hasName => !StringUtils.isEmpty("$nameGiven$nameMiddle$nameFamily$nameSuffix$namePrefix"); + bool get hasName => !StringUtils.isEmpty( + "$nameGiven$nameMiddle$nameFamily$nameSuffix$namePrefix"); bool get hasLabel => groupList.isNotEmpty; @@ -152,7 +154,8 @@ class ContactData { bool get hasAnySocial => hasGit || hasTwitter; - bool hasSameSocial(ContactData other) => other.twitterHandle == twitterHandle && other.gitUsername == gitUsername; + bool hasSameSocial(ContactData other) => + other.twitterHandle == twitterHandle && other.gitUsername == gitUsername; bool hasSocialOfType(SocialActivityType type) { if (type == SocialActivityType.Git) return hasGit; @@ -172,7 +175,8 @@ class ContactData { String get searchable => _searchable; - String _getSearchableFields() => "$nameGiven $nameMiddle $nameFamily $nameMiddlePhonetic $nameGivenPhonetic " + String _getSearchableFields() => + "$nameGiven $nameMiddle $nameFamily $nameMiddlePhonetic $nameGivenPhonetic " "$namePrefix $nameSuffix $nameFull $twitterHandle $gitUsername $notes $birthday $nickname" "$jobTitle $jobDepartment $jobCompany ${phoneList.map((x) => x.number).join(",")}" "${addressList.map((x) => x.getFullAddress()).join(",")}" @@ -197,7 +201,8 @@ class ContactData { List get allDates { //Need to explicitly cast x as DateMixin, otherwise will throw CastError when trying to add birthday - List dates = hasEvents ? eventList.map((x) => x as DateMixin).toList() : []; + List dates = + hasEvents ? eventList.map((x) => x as DateMixin).toList() : []; if (hasValidDateForBirthday) { dates.add(birthday); } @@ -213,7 +218,7 @@ class ContactData { Map toJson() => _$ContactDataToJson(this); @override - bool operator==(covariant ContactData other) => other.id == id; + bool operator ==(covariant ContactData other) => other.id == id; @override int get hashCode => id.hashCode; @@ -233,14 +238,17 @@ class AddressData { AddressData(); - get isEmpty => StringUtils.isEmpty("$street$poBox$neighborhood$city$region$postcode$country$type"); + get isEmpty => StringUtils.isEmpty( + "$street$poBox$neighborhood$city$region$postcode$country$type"); - factory AddressData.fromJson(Map json) => _$AddressDataFromJson(json); + factory AddressData.fromJson(Map json) => + _$AddressDataFromJson(json); Map toJson() => _$AddressDataToJson(this); String getFullAddress() { - String ss(String value, [String? extra]) => StringUtils.safeGet(value, extra); + String ss(String value, [String? extra]) => + StringUtils.safeGet(value, extra); String streetAddress = "${ss(street, ", ")}${ss(formattedAddress)}"; String address = "${ss(streetAddress, " \n")}"; @@ -272,7 +280,8 @@ class InstantMessageData { get isEmpty => StringUtils.isEmpty("$username$type"); - factory InstantMessageData.fromJson(Map json) => _$InstantMessageDataFromJson(json); + factory InstantMessageData.fromJson(Map json) => + _$InstantMessageDataFromJson(json); Map toJson() => _$InstantMessageDataToJson(this); } @@ -287,7 +296,8 @@ class PhoneData { get isEmpty => StringUtils.isEmpty("$number$type"); - factory PhoneData.fromJson(Map json) => _$PhoneDataFromJson(json); + factory PhoneData.fromJson(Map json) => + _$PhoneDataFromJson(json); Map toJson() => _$PhoneDataToJson(this); } @@ -301,7 +311,8 @@ class WebsiteData { get isEmpty => StringUtils.isEmpty("$href$type"); - factory WebsiteData.fromJson(Map json) => _$WebsiteDataFromJson(json); + factory WebsiteData.fromJson(Map json) => + _$WebsiteDataFromJson(json); Map toJson() => _$WebsiteDataToJson(this); } @@ -315,7 +326,8 @@ class EmailData { get isEmpty => StringUtils.isEmpty("$value$type"); - factory EmailData.fromJson(Map json) => _$EmailDataFromJson(json); + factory EmailData.fromJson(Map json) => + _$EmailDataFromJson(json); Map toJson() => _$EmailDataToJson(this); } @@ -329,7 +341,8 @@ class RelationData { get isEmpty => StringUtils.isEmpty("$person$type"); - factory RelationData.fromJson(Map json) => _$RelationDataFromJson(json); + factory RelationData.fromJson(Map json) => + _$RelationDataFromJson(json); Map toJson() => _$RelationDataToJson(this); } @@ -345,7 +358,8 @@ class EventData with DateMixin { get isEmpty => date == DateTime(0, 1, 1) || date.toString().isEmpty; - factory EventData.fromJson(Map json) => _$EventDataFromJson(json); + factory EventData.fromJson(Map json) => + _$EventDataFromJson(json); Map toJson() => _$EventDataToJson(this); } @@ -361,7 +375,8 @@ class BirthdayData with DateMixin { get isEmpty => StringUtils.isEmpty("$text"); - factory BirthdayData.fromJson(Map json) => _$BirthdayDataFromJson(json); + factory BirthdayData.fromJson(Map json) => + _$BirthdayDataFromJson(json); Map toJson() => _$BirthdayDataToJson(this); } diff --git a/flokk_src/lib/data/git_event_data.dart b/flokk_src/lib/data/git_event_data.dart index d876970..d528d92 100644 --- a/flokk_src/lib/data/git_event_data.dart +++ b/flokk_src/lib/data/git_event_data.dart @@ -18,7 +18,10 @@ class GitEvent implements DateSortable { GitEvent(); factory GitEvent.fromJson(Map json) { - return GitEvent()..event = json["event"] == null ? Event() : Event.fromJson(json["event"] as Map); + return GitEvent() + ..event = json["event"] == null + ? Event() + : Event.fromJson(json["event"] as Map); } Map toJson() => {"event": event}; diff --git a/flokk_src/lib/data/git_repo_data.dart b/flokk_src/lib/data/git_repo_data.dart index 57c0354..ebdff4e 100644 --- a/flokk_src/lib/data/git_repo_data.dart +++ b/flokk_src/lib/data/git_repo_data.dart @@ -15,9 +15,14 @@ class GitRepo { factory GitRepo.fromJson(Map json) { return GitRepo() - ..repository = json["repository"] == null ? Repository() : Repository.fromJson(json["repository"] as Map) - ..lastUpdated = json["lastUpdated"] == null ? Dates.epoch : DateTime.parse(json['lastUpdated'] as String); + ..repository = json["repository"] == null + ? Repository() + : Repository.fromJson(json["repository"] as Map) + ..lastUpdated = json["lastUpdated"] == null + ? Dates.epoch + : DateTime.parse(json['lastUpdated'] as String); } - Map toJson() => {"repository": repository, "lastUpdated": lastUpdated.toIso8601String()}; + Map toJson() => + {"repository": repository, "lastUpdated": lastUpdated.toIso8601String()}; } diff --git a/flokk_src/lib/data/group_data.dart b/flokk_src/lib/data/group_data.dart index 872c1cf..ca52003 100644 --- a/flokk_src/lib/data/group_data.dart +++ b/flokk_src/lib/data/group_data.dart @@ -13,12 +13,13 @@ class GroupData { GroupData(); - factory GroupData.fromJson(Map json) => _$GroupDataFromJson(json); + factory GroupData.fromJson(Map json) => + _$GroupDataFromJson(json); Map toJson() => _$GroupDataToJson(this); @override - bool operator==(covariant GroupData other) => other.id == id; + bool operator ==(covariant GroupData other) => other.id == id; @override int get hashCode => id.hashCode; diff --git a/flokk_src/lib/data/social_contact_data.dart b/flokk_src/lib/data/social_contact_data.dart index d296dd0..55f9b01 100644 --- a/flokk_src/lib/data/social_contact_data.dart +++ b/flokk_src/lib/data/social_contact_data.dart @@ -7,14 +7,16 @@ import 'package:flokk/data/tweet_data.dart'; class SocialContactData { /* Populated at runtime */ ContactData contact = ContactData(); - List tweets = const[]; - List gitEvents = const[]; + List tweets = const []; + List gitEvents = const []; //The number of new tweets since the last time user checked (populates the indicator) - List get newTweets => tweets.where((x) => x.createdAt.isAfter(lastCheckedTweets)).toList(); + List get newTweets => + tweets.where((x) => x.createdAt.isAfter(lastCheckedTweets)).toList(); //The number of new git events since the last time user checked (populates the indicator) - List get newGits => gitEvents.where((x) => x.createdAt.isAfter(lastCheckedGit)).toList(); + List get newGits => + gitEvents.where((x) => x.createdAt.isAfter(lastCheckedGit)).toList(); //Used to determine the level of activity for most active int get points { @@ -63,12 +65,18 @@ class SocialContactData { factory SocialContactData.fromJson(Map json) { return SocialContactData() ..contactId = json["contactId"] as String - ..lastCheckedTweets = - json["lastCheckedTweets"] == null ? Dates.epoch : DateTime.parse(json["lastCheckedTweets"] as String) - ..lastCheckedGit = json["lastCheckedGit"] == null ? Dates.epoch : DateTime.parse(json["lastCheckedGit"] as String) - ..lastUpdatedTwitter = - json["lastUpdatedTwitter"] == null ? Dates.epoch : DateTime.parse(json["lastUpdatedTwitter"] as String) - ..lastUpdatedGit = json["lastUpdatedGit"] == null ? Dates.epoch : DateTime.parse(json["lastUpdatedGit"] as String); + ..lastCheckedTweets = json["lastCheckedTweets"] == null + ? Dates.epoch + : DateTime.parse(json["lastCheckedTweets"] as String) + ..lastCheckedGit = json["lastCheckedGit"] == null + ? Dates.epoch + : DateTime.parse(json["lastCheckedGit"] as String) + ..lastUpdatedTwitter = json["lastUpdatedTwitter"] == null + ? Dates.epoch + : DateTime.parse(json["lastUpdatedTwitter"] as String) + ..lastUpdatedGit = json["lastUpdatedGit"] == null + ? Dates.epoch + : DateTime.parse(json["lastUpdatedGit"] as String); } Map toJson() { diff --git a/flokk_src/lib/data/tweet_data.dart b/flokk_src/lib/data/tweet_data.dart index aa4f5ea..58dd6e6 100644 --- a/flokk_src/lib/data/tweet_data.dart +++ b/flokk_src/lib/data/tweet_data.dart @@ -105,7 +105,7 @@ class Tweet implements DateSortable { Map toJson() => _$TweetToJson(this); @override - bool operator==(covariant Tweet other) => other.id == id; + bool operator ==(covariant Tweet other) => other.id == id; @override int get hashCode => id.hashCode; diff --git a/flokk_src/lib/data/twitter_user_data.dart b/flokk_src/lib/data/twitter_user_data.dart index 385cb9b..347fb97 100644 --- a/flokk_src/lib/data/twitter_user_data.dart +++ b/flokk_src/lib/data/twitter_user_data.dart @@ -43,7 +43,8 @@ class TwitterUser { TwitterUser(); - factory TwitterUser.fromJson(Map json) => _$TwitterUserFromJson(json); + factory TwitterUser.fromJson(Map json) => + _$TwitterUserFromJson(json); Map toJson() => _$TwitterUserToJson(this); } diff --git a/flokk_src/lib/main.dart b/flokk_src/lib/main.dart index af033b0..aab1ab9 100644 --- a/flokk_src/lib/main.dart +++ b/flokk_src/lib/main.dart @@ -22,19 +22,23 @@ import 'package:provider/provider.dart'; import 'package:universal_platform/universal_platform.dart'; //Developer hook to force login while testing locally (sidesteps Oauth flow) -const bool kForceWebLogin = bool.fromEnvironment('flokk.forceWebLogin', defaultValue: false); +const bool kForceWebLogin = + bool.fromEnvironment('flokk.forceWebLogin', defaultValue: false); bool tryAndLoadDevSpike(BuildContext c) { Widget? spike; /// Load spike if we have one - if (spike != null) AppGlobals.nav?.pushReplacement(PageRoutes.fade(() => spike)); + if (spike != null) + AppGlobals.nav?.pushReplacement(PageRoutes.fade(() => spike)); return spike != null; } void main() { /// Need to add this in order to run on Desktop. See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override - if (UniversalPlatform.isWindows || UniversalPlatform.isLinux || UniversalPlatform.isMacOS) { + if (UniversalPlatform.isWindows || + UniversalPlatform.isLinux || + UniversalPlatform.isMacOS) { debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; } @@ -134,7 +138,8 @@ class _MainAppState extends State { // TODO: Use platform brightness to determine default theme. // MediaQuery.of(context).platformBrightness; /// Bind to AppModel.theme and get current theme - ThemeType themeType = context.select((value) => value.theme); + ThemeType themeType = + context.select((value) => value.theme); AppTheme theme = AppTheme.fromType(themeType); /// Disable shadows on web builds for better performance diff --git a/flokk_src/lib/models/abstract_model.dart b/flokk_src/lib/models/abstract_model.dart index aa47ce9..46b9f50 100644 --- a/flokk_src/lib/models/abstract_model.dart +++ b/flokk_src/lib/models/abstract_model.dart @@ -57,11 +57,15 @@ abstract class AbstractModel extends ChangeNotifier { } List toList(dynamic json, dynamic Function(dynamic) fromJson) { - final List list = (json as Iterable?)?.map((e) { - return e == null ? e : fromJson(e) as T?; - }).where((e) => e != null).whereType().toList() ?? []; + final List list = (json as Iterable?) + ?.map((e) { + return e == null ? e : fromJson(e) as T?; + }) + .where((e) => e != null) + .whereType() + .toList() ?? + []; return list; } } - diff --git a/flokk_src/lib/models/app_model.dart b/flokk_src/lib/models/app_model.dart index 3beb06a..d92e102 100644 --- a/flokk_src/lib/models/app_model.dart +++ b/flokk_src/lib/models/app_model.dart @@ -62,7 +62,8 @@ class AppModel extends AbstractModel { /// ///////////////////////////////////////////////// /// Current dashboard sections (serialized) DashboardContactsSectionType get dashContactsSection => _dashContactsSection; - DashboardContactsSectionType _dashContactsSection = DashboardContactsSectionType.Favorites; + DashboardContactsSectionType _dashContactsSection = + DashboardContactsSectionType.Favorites; set dashContactsSection(DashboardContactsSectionType value) { _dashContactsSection = value; @@ -70,7 +71,8 @@ class AppModel extends AbstractModel { } DashboardSocialSectionType get dashSocialSection => _dashSocialSection; - DashboardSocialSectionType _dashSocialSection = DashboardSocialSectionType.All; + DashboardSocialSectionType _dashSocialSection = + DashboardSocialSectionType.All; set dashSocialSection(DashboardSocialSectionType value) { _dashSocialSection = value; @@ -82,7 +84,8 @@ class AppModel extends AbstractModel { ContactData get selectedContact => _selectedContact ?? ContactData(); ContactData? _selectedContact; - void touchSelectedSocial() => contactsModel.touchSocialById(selectedContact.id); + void touchSelectedSocial() => + contactsModel.touchSocialById(selectedContact.id); /// Current selected edit target, controls visibility of the edit panel set selectedContact(ContactData value) { @@ -141,8 +144,10 @@ class AppModel extends AbstractModel { var v = ThemeType.values; int theme = json["_theme"] ?? 0; _theme = v[theme.clamp(0, v.length)]; - _dashContactsSection = DashboardContactsSectionType.values[json['_dashContactsSection'] ?? 0]; - _dashSocialSection = DashboardSocialSectionType.values[json['_dashSocialSection'] ?? 0]; + _dashContactsSection = + DashboardContactsSectionType.values[json['_dashContactsSection'] ?? 0]; + _dashSocialSection = + DashboardSocialSectionType.values[json['_dashSocialSection'] ?? 0]; version = json['version']; } @@ -156,6 +161,8 @@ class AppModel extends AbstractModel { /// [SB] Just for easy testing, remove later void nextTheme() { - theme = (theme == ThemeType.FlockGreen_Dark) ? ThemeType.FlockGreen : ThemeType.FlockGreen_Dark; + theme = (theme == ThemeType.FlockGreen_Dark) + ? ThemeType.FlockGreen + : ThemeType.FlockGreen_Dark; } } diff --git a/flokk_src/lib/models/auth_model.dart b/flokk_src/lib/models/auth_model.dart index 6abf8ca..8bd7161 100644 --- a/flokk_src/lib/models/auth_model.dart +++ b/flokk_src/lib/models/auth_model.dart @@ -64,7 +64,9 @@ class AuthModel extends AbstractModel { ..googleRefreshToken = json["googleRefreshToken"] ..googleSyncToken = json["googleSyncToken"] ..googleEmail = json["googleEmail"] - .._expiry = json["_expiry"] != null ? DateTime.parse(json["_expiry"]) : Dates.epoch; + .._expiry = json["_expiry"] != null + ? DateTime.parse(json["_expiry"]) + : Dates.epoch; ; } diff --git a/flokk_src/lib/models/contacts_model.dart b/flokk_src/lib/models/contacts_model.dart index 2273f45..4602022 100644 --- a/flokk_src/lib/models/contacts_model.dart +++ b/flokk_src/lib/models/contacts_model.dart @@ -34,14 +34,18 @@ class ContactsModel extends AbstractModel { notifyListeners(); } - GroupData getGroupById(String value) => _allGroups.firstWhere((g) => g.id == value, orElse: () => GroupData()); + GroupData getGroupById(String value) => + _allGroups.firstWhere((g) => g.id == value, orElse: () => GroupData()); - GroupData getGroupByName(String value) => _allGroups.firstWhere((g) => g.name == value, orElse: () => GroupData()); + GroupData getGroupByName(String value) => + _allGroups.firstWhere((g) => g.name == value, orElse: () => GroupData()); //Contacts List - List get activeContacts => allContacts.where((c) => !c.isDeleted).toList(); + List get activeContacts => + allContacts.where((c) => !c.isDeleted).toList(); - List get starred => allContacts.where((c) => c.isStarred).toList(); + List get starred => + allContacts.where((c) => c.isStarred).toList(); List get allContacts => _allContacts; List _allContacts = []; @@ -52,7 +56,8 @@ class ContactsModel extends AbstractModel { notifyListeners(); } - ContactData getContactById(String id) => _allContacts.firstWhere((c) => c.id == id, orElse: () => ContactData()); + ContactData getContactById(String id) => + _allContacts.firstWhere((c) => c.id == id, orElse: () => ContactData()); void addContact(ContactData contact) { _allContacts.add(contact); @@ -120,16 +125,20 @@ class ContactsModel extends AbstractModel { } bool canRefreshTweetsFor(String twitterHandle) { - DateTime lastUpdate = getSocialContactByTwitter(twitterHandle).lastUpdatedTwitter; + DateTime lastUpdate = + getSocialContactByTwitter(twitterHandle).lastUpdatedTwitter; return DateTime.now().difference(lastUpdate) > tweetsCooldown; } - bool get canRefreshContactGroups => DateTime.now().difference(lastUpdatedGroups) > contactGroupsCooldown; + bool get canRefreshContactGroups => + DateTime.now().difference(lastUpdatedGroups) > contactGroupsCooldown; //Updates the timestamps when social feeds are refreshed for contact - void updateSocialTimestamps({String twitterHandle = "", String gitUsername = ""}) { + void updateSocialTimestamps( + {String twitterHandle = "", String gitUsername = ""}) { if (twitterHandle.isNotEmpty) { - getSocialContactByTwitter(twitterHandle).lastUpdatedTwitter = DateTime.now(); + getSocialContactByTwitter(twitterHandle).lastUpdatedTwitter = + DateTime.now(); } if (gitUsername.isNotEmpty) { getSocialContactByGit(gitUsername).lastUpdatedGit = DateTime.now(); @@ -137,21 +146,29 @@ class ContactsModel extends AbstractModel { } void updateContactDataGithubValidity(String gitUsername, bool isValid) { - allContacts.firstWhere((x) => x.gitUsername == gitUsername, orElse: () => ContactData()).hasValidGit = isValid; + allContacts + .firstWhere((x) => x.gitUsername == gitUsername, + orElse: () => ContactData()) + .hasValidGit = isValid; } void updateContactDataTwitterValidity(String twitterHandle, bool isValid) { - allContacts.firstWhere((x) => x.twitterHandle == twitterHandle, orElse: () => ContactData()).hasValidTwitter = - isValid; + allContacts + .firstWhere((x) => x.twitterHandle == twitterHandle, + orElse: () => ContactData()) + .hasValidTwitter = isValid; } ContactData getContactByGit(String gitUsername) => - allContacts.firstWhere((x) => x.gitUsername == gitUsername, orElse: () => ContactData()); + allContacts.firstWhere((x) => x.gitUsername == gitUsername, + orElse: () => ContactData()); ContactData getContactByTwitter(String twitterHandle) => - allContacts.firstWhere((x) => x.twitterHandle == twitterHandle, orElse: () => ContactData()); + allContacts.firstWhere((x) => x.twitterHandle == twitterHandle, + orElse: () => ContactData()); - SocialContactData getSocialContactByGit(String gitUsername) => getSocialById(getContactByGit(gitUsername).id); + SocialContactData getSocialContactByGit(String gitUsername) => + getSocialById(getContactByGit(gitUsername).id); SocialContactData getSocialContactByTwitter(String twitterHandle) => getSocialById(getContactByTwitter(twitterHandle).id); @@ -161,30 +178,38 @@ class ContactsModel extends AbstractModel { allSocialContacts..sort((a, b) => b.points.compareTo(a.points)); //Get a list of contacts with the most recent activity - List get mostRecentSocialContacts => - allSocialContacts..sort((a, b) => (b.latestActivity.createdAt).compareTo(a.latestActivity.createdAt)); + List get mostRecentSocialContacts => allSocialContacts + ..sort((a, b) => + (b.latestActivity.createdAt).compareTo(a.latestActivity.createdAt)); SocialContactData getSocialById(String id) { if (id.isEmpty) return SocialContactData(); - return allSocialContacts.firstWhere((c) => c.contactId == id, orElse: () => SocialContactData()); + return allSocialContacts.firstWhere((c) => c.contactId == id, + orElse: () => SocialContactData()); } //Get a list of contacts with upcoming dates (repeated contacts are expected if they have multiple events that are upcoming) List> get upcomingDateContacts { //List of all dates (birthday and events) with their contact id List> flattenedDates = allContacts - .map((contact) => contact.allDates.map((x) => Tuple2(contact.id, x)).toList()) + .map((contact) => contact.allDates + .map((x) => Tuple2(contact.id, x)) + .toList()) .toList() .expand((element) => element) - .where((element) => element.item2.daysTilAnniversary < 90) //limit to upcoming dates for next 3 months + .where((element) => + element.item2.daysTilAnniversary < + 90) //limit to upcoming dates for next 3 months .toList(); //Sort by the closest upcoming dates - flattenedDates.sort((a, b) => a.item2.daysTilAnniversary.compareTo(b.item2.daysTilAnniversary)); + flattenedDates.sort((a, b) => + a.item2.daysTilAnniversary.compareTo(b.item2.daysTilAnniversary)); List> contactsWithDates = []; for (var n in flattenedDates) { - contactsWithDates.add(Tuple2(getContactById(n.item1), n.item2)); + contactsWithDates.add( + Tuple2(getContactById(n.item1), n.item2)); } return contactsWithDates; } @@ -217,7 +242,8 @@ class ContactsModel extends AbstractModel { void _updateSocialContacts() { //clean up any social contacts that are NOT found in all contacts - _allSocialContacts.removeWhere((x) => !_allContacts.any((c) => c.id == x.contactId)); + _allSocialContacts + .removeWhere((x) => !_allContacts.any((c) => c.id == x.contactId)); //create social contact if needed, otherwise just update tweets/events for (var n in _allContacts) { @@ -229,7 +255,8 @@ class ContactsModel extends AbstractModel { ..gitEvents = gitModel.getEventsByContact(n) ..tweets = twitterModel.getTweetsByContact(n)); } else { - SocialContactData socialContact = _allSocialContacts.firstWhere((x) => x.contactId == n.id); + SocialContactData socialContact = + _allSocialContacts.firstWhere((x) => x.contactId == n.id); socialContact.contact = n; socialContact.gitEvents = gitModel.getEventsByContact(n); socialContact.tweets = twitterModel.getTweetsByContact(n); @@ -251,15 +278,21 @@ class ContactsModel extends AbstractModel { //Json Serialization @override ContactsModel copyFromJson(Map value) { - _allContacts = toList(value['_allContacts'], (j) => ContactData.fromJson(j)); + _allContacts = + toList(value['_allContacts'], (j) => ContactData.fromJson(j)); _allGroups = toList(value['_allGroups'], (j) => GroupData.fromJson(j)); - _allSocialContacts = toList(value['_allSocialContacts'], (j) => SocialContactData.fromJson(j)); + _allSocialContacts = toList( + value['_allSocialContacts'], (j) => SocialContactData.fromJson(j)); _updateSocialContacts(); return this; } @override Map toJson() { - return {'_allContacts': _allContacts, '_allGroups': _allGroups, '_allSocialContacts': _allSocialContacts}; + return { + '_allContacts': _allContacts, + '_allGroups': _allGroups, + '_allSocialContacts': _allSocialContacts + }; } } diff --git a/flokk_src/lib/models/github_model.dart b/flokk_src/lib/models/github_model.dart index 50e5f8e..da7eb6a 100644 --- a/flokk_src/lib/models/github_model.dart +++ b/flokk_src/lib/models/github_model.dart @@ -8,7 +8,8 @@ import 'package:github/github.dart'; import 'package:tuple/tuple.dart'; class GithubModel extends AbstractModel { - final expiry = Duration(days: 30); //the period of which to cull events based on createdAt + final expiry = Duration( + days: 30); //the period of which to cull events based on createdAt final repoStaleTime = Duration(hours: 72); ContactsModel contactsModel; @@ -31,17 +32,22 @@ class GithubModel extends AbstractModel { @override GithubModel copyFromJson(Map json) { - _eventsHash = (json["_eventsHash"] as Map?)?.map((key, value) => - MapEntry>(key, (value as List?)?.map((x) => GitEvent.fromJson(x)).toList() ?? [])) ?? + _eventsHash = (json["_eventsHash"] as Map?)?.map( + (key, value) => MapEntry>( + key, + (value as List?)?.map((x) => GitEvent.fromJson(x)).toList() ?? + [])) ?? {}; - _reposHash = (json["_reposHash"] as Map?) - ?.map((key, value) => MapEntry(key, GitRepo.fromJson(value))) ?? + _reposHash = (json["_reposHash"] as Map?)?.map( + (key, value) => + MapEntry(key, GitRepo.fromJson(value))) ?? {}; return this; } @override - Map toJson() => {"_eventsHash": _eventsHash, "_reposHash": _reposHash}; + Map toJson() => + {"_eventsHash": _eventsHash, "_reposHash": _reposHash}; /// ////////////////////////////////////////////////////////////////// /// Public API @@ -59,7 +65,9 @@ class GithubModel extends AbstractModel { bool repoIsStale(String repoFullName) => !repoExists(repoFullName) || - DateTime.now().difference(_reposHash[repoFullName]?.lastUpdated ?? Dates.epoch) > repoStaleTime; + DateTime.now().difference( + _reposHash[repoFullName]?.lastUpdated ?? Dates.epoch) > + repoStaleTime; //Get all user repos List get allRepos { @@ -83,7 +91,8 @@ class GithubModel extends AbstractModel { List events = getEventsByContact(contact); //Distinct (no duplicates) list of repo names from contact events - List repoNames = events.map((x) => x.event.repo?.name ?? "").toSet().toList(); + List repoNames = + events.map((x) => x.event.repo?.name ?? "").toSet().toList(); //Get repos either owned by contact or is part of the contact events List repos = _reposHash.values @@ -120,14 +129,16 @@ class GithubModel extends AbstractModel { .map((x) => x.event.actor?.login) .toSet() .toList() //get distinct git usernames for each event - .map((x) => contactsModel.getContactByGit(x ?? "")) //get contact by gitusername + .map((x) => contactsModel + .getContactByGit(x ?? "")) //get contact by gitusername .toList(); //Get the latest date from the events associated with this repo or else fall back to repository.updatedAt associatedEvents.sort((a, b) => b.createdAt.compareTo(a.createdAt)); - DateTime latestActivityDate = (associatedEvents.isNotEmpty && n.repository.updatedAt != null) - ? associatedEvents.first.createdAt - : n.repository.updatedAt ?? Dates.epoch; + DateTime latestActivityDate = + (associatedEvents.isNotEmpty && n.repository.updatedAt != null) + ? associatedEvents.first.createdAt + : n.repository.updatedAt ?? Dates.epoch; if (associatedContacts.isNotEmpty) { popular.add(Tuple2( @@ -153,7 +164,9 @@ class GithubModel extends AbstractModel { for (var n in sorted) { n.repository = _reposHash[n.event.repo?.name]?.repository ?? Repository( - id: n.event.repo?.id ?? 0, name: n.event.repo?.name ?? "", htmlUrl: n.event.repo?.htmlUrl ?? ""); + id: n.event.repo?.id ?? 0, + name: n.event.repo?.name ?? "", + htmlUrl: n.event.repo?.htmlUrl ?? ""); } return sorted; @@ -166,7 +179,9 @@ class GithubModel extends AbstractModel { void addEvents(String gitUsername, List events) { final current = DateTime.now(); - _eventsHash[gitUsername] = events.where((x) => (current.difference(x.createdAt)) < expiry).toList(); + _eventsHash[gitUsername] = events + .where((x) => (current.difference(x.createdAt)) < expiry) + .toList(); notifyListeners(); } diff --git a/flokk_src/lib/models/twitter_model.dart b/flokk_src/lib/models/twitter_model.dart index 8e425ad..0ce4997 100644 --- a/flokk_src/lib/models/twitter_model.dart +++ b/flokk_src/lib/models/twitter_model.dart @@ -6,7 +6,8 @@ import 'package:flokk/models/contacts_model.dart'; import 'package:tuple/tuple.dart'; class TwitterModel extends AbstractModel { - final expiry = Duration(days: 30); //the period of which to cull tweets based on createdAt + final expiry = Duration( + days: 30); //the period of which to cull tweets based on createdAt ContactsModel contactsModel; @@ -25,15 +26,25 @@ class TwitterModel extends AbstractModel { @override TwitterModel copyFromJson(Map json) { _twitterAccessToken = json["_twitterAccessToken"] ?? ""; - Map jsonTweetHash = json["_tweetHash"] ?? {}; - _tweetHash = jsonTweetHash.map((key, value) => MapEntry>( - key, (value as List?)?.where((value) => value != null).map((x) => Tweet.fromJson(x)).toList() ?? [])); + Map jsonTweetHash = + json["_tweetHash"] ?? {}; + _tweetHash = jsonTweetHash.map((key, value) => + MapEntry>( + key, + (value as List?) + ?.where((value) => value != null) + .map((x) => Tweet.fromJson(x)) + .toList() ?? + [])); return this; } @override Map toJson() { - return {"_twitterAccessToken": _twitterAccessToken, "_tweetHash": _tweetHash}; + return { + "_twitterAccessToken": _twitterAccessToken, + "_tweetHash": _tweetHash + }; } /// ////////////////////////////////////////////////////////////////// @@ -91,7 +102,9 @@ class TwitterModel extends AbstractModel { void addTweets(String twitterHandle, List tweets) { final current = DateTime.now(); - _tweetHash[twitterHandle] = tweets.where((x) => (current.difference(x.createdAt)) < expiry).toList(); + _tweetHash[twitterHandle] = tweets + .where((x) => (current.difference(x.createdAt)) < expiry) + .toList(); notifyListeners(); } diff --git a/flokk_src/lib/services/github_rest_service.dart b/flokk_src/lib/services/github_rest_service.dart index 6b14ee2..d0bc0c5 100644 --- a/flokk_src/lib/services/github_rest_service.dart +++ b/flokk_src/lib/services/github_rest_service.dart @@ -19,10 +19,12 @@ class GithubRestService { }; } - Future>> getUserEvents(String githubUsername) async { + Future>> getUserEvents( + String githubUsername) async { String url = "https://api.github.com/users/$githubUsername/events"; - HttpResponse response = await HttpClient.get(url, headers: _getAuthHeader()); + HttpResponse response = + await HttpClient.get(url, headers: _getAuthHeader()); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); List events = []; @@ -35,10 +37,12 @@ class GithubRestService { return ServiceResult(events, response); } - Future>> getUserRepos(String githubUsername) async { + Future>> getUserRepos( + String githubUsername) async { String url = "https://api.github.com/users/$githubUsername/repos"; - HttpResponse response = await HttpClient.get(url, headers: _getAuthHeader()); + HttpResponse response = + await HttpClient.get(url, headers: _getAuthHeader()); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); List repos = []; @@ -56,7 +60,8 @@ class GithubRestService { Future> getRepo(String repoName) async { String url = "https://api.github.com/repos/$repoName"; - HttpResponse response = await HttpClient.get(url, headers: _getAuthHeader()); + HttpResponse response = + await HttpClient.get(url, headers: _getAuthHeader()); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); GitRepo? repo; diff --git a/flokk_src/lib/services/google_rest/google_rest_auth_service.dart b/flokk_src/lib/services/google_rest/google_rest_auth_service.dart index 3376a4f..9cacad1 100644 --- a/flokk_src/lib/services/google_rest/google_rest_auth_service.dart +++ b/flokk_src/lib/services/google_rest/google_rest_auth_service.dart @@ -6,10 +6,12 @@ import 'package:flokk/_internal/utils/string_utils.dart'; import 'package:flokk/services/service_result.dart'; class GoogleRestAuthService { - final String discoveryUrl = "https://accounts.google.com/.well-known/openid-configuration"; + final String discoveryUrl = + "https://accounts.google.com/.well-known/openid-configuration"; final String authUrl = "https://oauth2.googleapis.com/token"; final String redirectUri = "https://oauth2.googleapis.com/callback"; - final String deviceCodeGrantType = "urn:ietf:params:oauth:grant-type:device_code"; + final String deviceCodeGrantType = + "urn:ietf:params:oauth:grant-type:device_code"; final String scope = "email https://www.googleapis.com/auth/contacts"; final String _clientId; @@ -45,21 +47,30 @@ class GoogleRestAuthService { return ServiceResult(null, discoverResponse); } - Future> authorizeDevice(String deviceCode) async => + Future> authorizeDevice( + String deviceCode) async => await _getAuthResults(deviceCode: deviceCode); Future> refresh(String refreshToken) async => await _getAuthResults(refreshToken: refreshToken); - Future> _getAuthResults({String deviceCode = "", String refreshToken = ""}) async { - String grant = !StringUtils.isEmpty(refreshToken) ? "refresh_token" : deviceCodeGrantType; - Map params = {"client_id": _clientId, "client_secret": _clientSecret, "grant_type": grant}; + Future> _getAuthResults( + {String deviceCode = "", String refreshToken = ""}) async { + String grant = !StringUtils.isEmpty(refreshToken) + ? "refresh_token" + : deviceCodeGrantType; + Map params = { + "client_id": _clientId, + "client_secret": _clientSecret, + "grant_type": grant + }; if (!StringUtils.isEmpty(refreshToken)) { params.putIfAbsent("refreshToken", () => refreshToken); } else { params.putIfAbsent("device_code", () => deviceCode); } - HttpResponse response = await HttpClient.post("$authUrl?${RESTUtils.encodeParams(params)}"); + HttpResponse response = + await HttpClient.post("$authUrl?${RESTUtils.encodeParams(params)}"); print("Response: ${response.statusCode} / ${response.body}"); GoogleAuthResults? results; if (response.success) { diff --git a/flokk_src/lib/services/google_rest/google_rest_contact_groups_service.dart b/flokk_src/lib/services/google_rest/google_rest_contact_groups_service.dart index 23d8650..852c6d0 100644 --- a/flokk_src/lib/services/google_rest/google_rest_contact_groups_service.dart +++ b/flokk_src/lib/services/google_rest/google_rest_contact_groups_service.dart @@ -8,7 +8,8 @@ import 'package:googleapis/people/v1.dart'; import 'package:tuple/tuple.dart'; class GoogleRestContactGroupsService { - Future, String>>> get(String accessToken, {String nextPageToken = ""}) async { + Future, String>>> get(String accessToken, + {String nextPageToken = ""}) async { String url = "https://people.googleapis.com/v1/contactGroups" "?access_token=$accessToken" "&pageSize=1000"; @@ -30,10 +31,12 @@ class GoogleRestContactGroupsService { groups.add(group); } } - return ServiceResult(Tuple2, String>(groups, token), response); + return ServiceResult( + Tuple2, String>(groups, token), response); } - Future> getById(String accessToken, String groupId) async { + Future> getById( + String accessToken, String groupId) async { String url = "https://people.googleapis.com/v1/$groupId" "?access_token=$accessToken" "&maxMembers=1000"; @@ -47,11 +50,13 @@ class GoogleRestContactGroupsService { return ServiceResult(group, response); } - Future> create(String accessToken, GroupData group) async { + Future> create( + String accessToken, GroupData group) async { String url = "https://people.googleapis.com/v1/contactGroups"; HttpResponse response = await HttpClient.post(url, - headers: {"Authorization": "Bearer $accessToken"}, body: jsonEncode({"contactGroup": groupToJson(group)})); + headers: {"Authorization": "Bearer $accessToken"}, + body: jsonEncode({"contactGroup": groupToJson(group)})); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); GroupData? newGroup; if (response.success == true) { @@ -61,7 +66,8 @@ class GoogleRestContactGroupsService { return ServiceResult(newGroup, response); } - Future> delete(String accessToken, GroupData group) async { + Future> delete( + String accessToken, GroupData group) async { String url = "https://people.googleapis.com/v1/${group.id}"; HttpResponse response = await HttpClient.delete( @@ -73,7 +79,8 @@ class GoogleRestContactGroupsService { } Future> modify(String accessToken, GroupData group, - {List addContacts = const[], List removeContacts = const[]}) async { + {List addContacts = const [], + List removeContacts = const []}) async { String url = "https://people.googleapis.com/v1/${group.id}/members:modify"; Map data = {}; @@ -93,11 +100,13 @@ class GoogleRestContactGroupsService { return ServiceResult(null, response); } - Future> set(String accessToken, GroupData group) async { + Future> set( + String accessToken, GroupData group) async { String url = "https://people.googleapis.com/v1/${group.id}"; HttpResponse response = await HttpClient.put(url, - headers: {"Authorization": "Bearer $accessToken"}, body: jsonEncode({"contactGroup": groupToJson(group)})); + headers: {"Authorization": "Bearer $accessToken"}, + body: jsonEncode({"contactGroup": groupToJson(group)})); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); GroupData? updatedContact; if (response.success == true) { diff --git a/flokk_src/lib/services/google_rest/google_rest_contacts_service.dart b/flokk_src/lib/services/google_rest/google_rest_contacts_service.dart index 3eb7862..83b4c88 100644 --- a/flokk_src/lib/services/google_rest/google_rest_contacts_service.dart +++ b/flokk_src/lib/services/google_rest/google_rest_contacts_service.dart @@ -72,7 +72,8 @@ class GoogleRestContactsService { //Debug hook to test many contacts, if the multiplier is > 1, it will clone your contacts list that many times. static int contactsMultiplier = 1; - Future> getAll(String accessToken, String syncToken) async { + Future> getAll( + String accessToken, String syncToken) async { List list = []; bool requestSyncToken = syncToken == ""; int retryCount = 0; @@ -117,9 +118,9 @@ class GoogleRestContactsService { //List of valid PersonFields can be found here https://developers.google.com/people/api/rest/v1/people.connections/list Future> get(String accessToken, {List personFields = const [], - String nextPageToken = "", - String syncToken = "", - bool requestSyncToken = true}) async { + String nextPageToken = "", + String syncToken = "", + bool requestSyncToken = true}) async { // Default to all person fields if none are passed if (personFields.isEmpty) { personFields = kAllPersonFields; @@ -149,7 +150,8 @@ class GoogleRestContactsService { newNextPageToken = data["nextPageToken"] ?? ""; newSyncToken = data["nextSyncToken"] ?? ""; List entries = data["connections"] ?? []; - print("token: $newNextPageToken ${entries.length} out of ${data["totalPeople"]}"); + print( + "token: $newNextPageToken ${entries.length} out of ${data["totalPeople"]}"); for (int i = 0, l = entries.length; i < l; i++) { ContactData c = contactFromJson(entries[i]); list.add(c); @@ -161,18 +163,24 @@ class GoogleRestContactsService { } } } - return ServiceResult(GetContactsResult(list, nextPageToken: nextPageToken, syncToken: newSyncToken), response); + return ServiceResult( + GetContactsResult(list, + nextPageToken: nextPageToken, syncToken: newSyncToken), + response); } //List of valid PersonFields can be found here https://developers.google.com/people/api/rest/v1/people/updateContact - Future> set(String accessToken, ContactData contact, {List personFields = const[]}) async { - if (personFields.isEmpty) - personFields = kAllUpdatePersonFields; - String url = "https://people.googleapis.com/v1/${contact.googleId}:updateContact?" + Future> set( + String accessToken, ContactData contact, + {List personFields = const []}) async { + if (personFields.isEmpty) personFields = kAllUpdatePersonFields; + String url = + "https://people.googleapis.com/v1/${contact.googleId}:updateContact?" "updatePersonFields=${personFields.join(',')}"; HttpResponse response = await HttpClient.patch(url, - headers: {"Authorization": "Bearer $accessToken"}, body: jsonEncode(contactToJson(contact))); + headers: {"Authorization": "Bearer $accessToken"}, + body: jsonEncode(contactToJson(contact))); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); ContactData updatedContact = ContactData(); if (response.success == true) { @@ -182,11 +190,13 @@ class GoogleRestContactsService { return ServiceResult(updatedContact, response); } - Future> create(String accessToken, ContactData contact) async { + Future> create( + String accessToken, ContactData contact) async { String url = "https://people.googleapis.com/v1/people:createContact"; HttpResponse response = await HttpClient.post(url, - headers: {"Authorization": "Bearer $accessToken"}, body: jsonEncode(contactToJson(contact))); + headers: {"Authorization": "Bearer $accessToken"}, + body: jsonEncode(contactToJson(contact))); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); ContactData newContact = ContactData(); if (response.success == true) { @@ -196,22 +206,31 @@ class GoogleRestContactsService { return ServiceResult(newContact, response); } - Future> delete(String accessToken, ContactData contact) async { - String url = "https://people.googleapis.com/v1/${contact.googleId}:deleteContact"; + Future> delete( + String accessToken, ContactData contact) async { + String url = + "https://people.googleapis.com/v1/${contact.googleId}:deleteContact"; - HttpResponse response = await HttpClient.delete(url, headers: {"Authorization": "Bearer $accessToken"}); + HttpResponse response = await HttpClient.delete(url, + headers: {"Authorization": "Bearer $accessToken"}); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); return ServiceResult(null, response); } //Takes a base64 encoded image - Future> updatePic(String accessToken, ContactData contact, String profilePic) async { - String url = "https://people.googleapis.com/v1/${contact.googleId}:updateContactPhoto"; + Future> updatePic( + String accessToken, ContactData contact, String profilePic) async { + String url = + "https://people.googleapis.com/v1/${contact.googleId}:updateContactPhoto"; - Map bodyJson = {"photoBytes": profilePic, "personFields": "names,photos"}; + Map bodyJson = { + "photoBytes": profilePic, + "personFields": "names,photos" + }; - HttpResponse response = - await HttpClient.patch(url, headers: {"Authorization": "Bearer $accessToken"}, body: jsonEncode(bodyJson)); + HttpResponse response = await HttpClient.patch(url, + headers: {"Authorization": "Bearer $accessToken"}, + body: jsonEncode(bodyJson)); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); ContactData updatedContact = ContactData(); if (response.success == true) { @@ -220,10 +239,13 @@ class GoogleRestContactsService { return ServiceResult(updatedContact, response); } - Future> deletePic(String accessToken, ContactData contact) async { - String url = "https://people.googleapis.com/v1/${contact.googleId}:deleteContactPhoto"; + Future> deletePic( + String accessToken, ContactData contact) async { + String url = + "https://people.googleapis.com/v1/${contact.googleId}:deleteContactPhoto"; - HttpResponse response = await HttpClient.delete(url, headers: {"Authorization": "Bearer $accessToken"}); + HttpResponse response = await HttpClient.delete(url, + headers: {"Authorization": "Bearer $accessToken"}); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); return ServiceResult(null, response); } @@ -283,7 +305,8 @@ class GoogleRestContactsService { [] ..eventList = p.events ?.map((x) => EventData() - ..date = DateTime(x.date?.year ?? 0, x.date?.month ?? 1, x.date?.day ?? 1) + ..date = DateTime( + x.date?.year ?? 0, x.date?.month ?? 1, x.date?.day ?? 1) ..type = x.formattedType ?? "") .toList() ?? [] @@ -303,7 +326,9 @@ class GoogleRestContactsService { if (p.birthdays?.isNotEmpty ?? false) { c.birthday = BirthdayData() ..date = DateTime( - p.birthdays?.first.date?.year ?? 0, p.birthdays?.first.date?.month ?? 1, p.birthdays?.first.date?.day ?? 1) + p.birthdays?.first.date?.year ?? 0, + p.birthdays?.first.date?.month ?? 1, + p.birthdays?.first.date?.day ?? 1) ..text = p.birthdays?.first.text ?? ""; if (c.birthday.date == DateTime(0, 1, 1)) { @@ -316,8 +341,9 @@ class GoogleRestContactsService { } if (p.userDefined?.isNotEmpty ?? false) { - c.customFields = - Map.fromIterable(p.userDefined ?? [], key: (x) => (x as UserDefined).key ?? "", value: (x) => (x as UserDefined).value ?? ""); + c.customFields = Map.fromIterable(p.userDefined ?? [], + key: (x) => (x as UserDefined).key ?? "", + value: (x) => (x as UserDefined).value ?? ""); /// Inject known custom fields into Contact, and remove from Map c.twitterHandle = c.customFields.remove(kTwitterParam) ?? ""; @@ -405,7 +431,9 @@ class GoogleRestContactsService { p.birthdays = [Birthday()..text = contact.birthday.text]; } - if (contact.hasGit || contact.hasTwitter || contact.customFields.isNotEmpty) { + if (contact.hasGit || + contact.hasTwitter || + contact.customFields.isNotEmpty) { /// Inject known custom fields back into the payload void addUserDefined(String key, dynamic value) { if (value == null) return; @@ -420,7 +448,8 @@ class GoogleRestContactsService { contact.customFields.forEach(addUserDefined); /// Inject our own, known fields - if (contact.hasTwitter) addUserDefined(kTwitterParam, contact.twitterHandle); + if (contact.hasTwitter) + addUserDefined(kTwitterParam, contact.twitterHandle); if (contact.hasGit) addUserDefined(kGitParam, contact.gitUsername); } //NOTE: Person.Photos are not needed in this, they are read-only @@ -433,5 +462,6 @@ class GetContactsResult { final String nextPageToken; final String syncToken; - GetContactsResult(this.contacts, {required this.nextPageToken, required this.syncToken}); + GetContactsResult(this.contacts, + {required this.nextPageToken, required this.syncToken}); } diff --git a/flokk_src/lib/services/google_rest/google_rest_service.dart b/flokk_src/lib/services/google_rest/google_rest_service.dart index 067621d..9b3c656 100644 --- a/flokk_src/lib/services/google_rest/google_rest_service.dart +++ b/flokk_src/lib/services/google_rest/google_rest_service.dart @@ -7,6 +7,8 @@ class GoogleRestService { static String kStarredGroupId = "contactGroups/starred"; final GoogleRestContactsService contacts = GoogleRestContactsService(); - final GoogleRestContactGroupsService groups = GoogleRestContactGroupsService(); - final GoogleRestAuthService auth = GoogleRestAuthService(ApiKeys().googleClientId, ApiKeys().googleClientSecret); + final GoogleRestContactGroupsService groups = + GoogleRestContactGroupsService(); + final GoogleRestAuthService auth = GoogleRestAuthService( + ApiKeys().googleClientId, ApiKeys().googleClientSecret); } diff --git a/flokk_src/lib/services/twitter_rest_service.dart b/flokk_src/lib/services/twitter_rest_service.dart index 2345bca..f9981ff 100644 --- a/flokk_src/lib/services/twitter_rest_service.dart +++ b/flokk_src/lib/services/twitter_rest_service.dart @@ -20,31 +20,38 @@ class TwitterRestService { final String auth = base64Encode(bytes); HttpResponse response = await HttpClient.post("$authUrl", - headers: {"Authorization": "Basic $auth", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"}, + headers: { + "Authorization": "Basic $auth", + "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" + }, body: "grant_type=client_credentials"); TwitterAuthResult? result; if (response.success) { Map data = jsonDecode(response.body); - result = TwitterAuthResult(tokenType: data["token_type"], accessToken: data["access_token"]); + result = TwitterAuthResult( + tokenType: data["token_type"], accessToken: data["access_token"]); } - return ServiceResult(result, response); } - Future>> getTweets(String accessToken, String screenName) async { - String url = "${proxy}https://api.twitter.com/1.1/statuses/user_timeline.json" + Future>> getTweets( + String accessToken, String screenName) async { + String url = + "${proxy}https://api.twitter.com/1.1/statuses/user_timeline.json" "?screen_name=$screenName" "&tweet_mode=extended"; - HttpResponse response = await HttpClient.get(url, headers: {"Authorization": "Bearer $accessToken"}); + HttpResponse response = await HttpClient.get(url, + headers: {"Authorization": "Bearer $accessToken"}); print("REQUEST: $url /// RESPONSE: ${response.statusCode}"); List tweets = []; if (response.success) { - List> tweetsData = List.from(jsonDecode(response.body)); + List> tweetsData = + List.from(jsonDecode(response.body)); for (int i = 0; i < tweetsData.length; i++) { Map data = tweetsData[i]; Tweet t = Tweet.fromJson(data); diff --git a/flokk_src/lib/strings.dart b/flokk_src/lib/strings.dart index 8110c5a..5a60e18 100644 --- a/flokk_src/lib/strings.dart +++ b/flokk_src/lib/strings.dart @@ -20,20 +20,31 @@ class _Strings { String LBL_STEP_X = "Step {0}"; String ERR_DEVICE_OAUTH_FAILED_TITLE = "Unable to connect to your account."; - String ERR_DEVICE_OAUTH_FAILED_MSG = "Please make sure you've completed the sign-in process in your browser."; + String ERR_DEVICE_OAUTH_FAILED_MSG = + "Please make sure you've completed the sign-in process in your browser."; String GOOGLE_OAUTH_TITLE = "GOOGLE SIGN-IN"; String GOOGLE_OAUTH_INSTRUCTIONS_1 = "In order to import your Google Contacts, you'll need to authorize this application using your web browser."; - String GOOGLE_OAUTH_INSTRUCTIONS_2 = "Copy this code to your clipboard by clicking the icon or selecting the text:"; - String GOOGLE_OAUTH_INSTRUCTIONS_3 = "Navigate to the following link in your web browser, and enter the above code:"; - String GOOGLE_OAUTH_INSTRUCTIONS_4 = "Press the button below when you've completed signup:"; + String GOOGLE_OAUTH_INSTRUCTIONS_2 = + "Copy this code to your clipboard by clicking the icon or selecting the text:"; + String GOOGLE_OAUTH_INSTRUCTIONS_3 = + "Navigate to the following link in your web browser, and enter the above code:"; + String GOOGLE_OAUTH_INSTRUCTIONS_4 = + "Press the button below when you've completed signup:"; } _Strings get S => _Strings.instance; extension AddSupplant on String { - String sup([dynamic v0, dynamic v1, dynamic v2, dynamic v3, dynamic v4, dynamic v5, dynamic v6]) { + String sup( + [dynamic v0, + dynamic v1, + dynamic v2, + dynamic v3, + dynamic v4, + dynamic v5, + dynamic v6]) { var _s = this; if (v0 != null) _s = _s.replaceAll("{0}", "$v0"); if (v1 != null) _s = _s.replaceAll("{1}", "$v1"); diff --git a/flokk_src/lib/styled_components/buttons/base_styled_button.dart b/flokk_src/lib/styled_components/buttons/base_styled_button.dart index b0ae6a9..52498c0 100644 --- a/flokk_src/lib/styled_components/buttons/base_styled_button.dart +++ b/flokk_src/lib/styled_components/buttons/base_styled_button.dart @@ -84,9 +84,15 @@ class _BaseStyledBtnState extends State { boxShadow: _isFocused ? [ BoxShadow( - color: theme.focus.withOpacity(0.25), offset: Offset.zero, blurRadius: 8.0, spreadRadius: 0.0), + color: theme.focus.withOpacity(0.25), + offset: Offset.zero, + blurRadius: 8.0, + spreadRadius: 0.0), BoxShadow( - color: widget.bgColor ?? theme.surface, offset: Offset.zero, blurRadius: 8.0, spreadRadius: -4.0), + color: widget.bgColor ?? theme.surface, + offset: Offset.zero, + blurRadius: 8.0, + spreadRadius: -4.0), ] : [], ), @@ -116,7 +122,7 @@ class _BaseStyledBtnState extends State { fillColor: Colors.transparent, hoverColor: widget.hoverColor ?? theme.surface, highlightColor: widget.downColor ?? theme.accent1.withOpacity(.1), - focusColor: widget.focusColor?? Colors.grey.withOpacity(0.35), + focusColor: widget.focusColor ?? Colors.grey.withOpacity(0.35), child: Opacity( child: Padding( padding: widget.contentPadding, @@ -124,7 +130,8 @@ class _BaseStyledBtnState extends State { ), opacity: widget.onPressed != null ? 1 : .7, ), - constraints: BoxConstraints(minHeight: widget.minHeight, minWidth: widget.minWidth), + constraints: BoxConstraints( + minHeight: widget.minHeight, minWidth: widget.minWidth), onPressed: widget.onPressed, shape: widget.shape ?? RoundedRectangleBorder( diff --git a/flokk_src/lib/styled_components/buttons/colored_icon_btn.dart b/flokk_src/lib/styled_components/buttons/colored_icon_btn.dart index 9910f2d..c6de758 100644 --- a/flokk_src/lib/styled_components/buttons/colored_icon_btn.dart +++ b/flokk_src/lib/styled_components/buttons/colored_icon_btn.dart @@ -16,7 +16,7 @@ class ColorShiftIconBtn extends StatelessWidget { final AssetImage icon; final double size; final Color? color; - final Color ?bgColor; + final Color? bgColor; final EdgeInsets padding; final double? minWidth; final double? minHeight; diff --git a/flokk_src/lib/styled_components/buttons/ok_cancel_btn_row.dart b/flokk_src/lib/styled_components/buttons/ok_cancel_btn_row.dart index b30231a..4a854d0 100644 --- a/flokk_src/lib/styled_components/buttons/ok_cancel_btn_row.dart +++ b/flokk_src/lib/styled_components/buttons/ok_cancel_btn_row.dart @@ -12,7 +12,11 @@ class OkCancelBtnRow extends StatelessWidget { final String? cancelLabel; const OkCancelBtnRow( - {Key? key, this.onOkPressed, this.onCancelPressed, this.okLabel, this.cancelLabel}) + {Key? key, + this.onOkPressed, + this.onCancelPressed, + this.okLabel, + this.cancelLabel}) : super(key: key); @override @@ -20,10 +24,13 @@ class OkCancelBtnRow extends StatelessWidget { return Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - if (onOkPressed != null) PrimaryTextBtn(okLabel ?? S.BTN_OK.toUpperCase(), onPressed: onOkPressed), + if (onOkPressed != null) + PrimaryTextBtn(okLabel ?? S.BTN_OK.toUpperCase(), + onPressed: onOkPressed), HSpace(Insets.m), if (onCancelPressed != null) - SecondaryTextBtn(cancelLabel ?? S.BTN_CANCEL.toUpperCase(), onPressed: onCancelPressed), + SecondaryTextBtn(cancelLabel ?? S.BTN_CANCEL.toUpperCase(), + onPressed: onCancelPressed), ], ); } diff --git a/flokk_src/lib/styled_components/buttons/primary_btn.dart b/flokk_src/lib/styled_components/buttons/primary_btn.dart index 0a4000a..0794a79 100644 --- a/flokk_src/lib/styled_components/buttons/primary_btn.dart +++ b/flokk_src/lib/styled_components/buttons/primary_btn.dart @@ -9,7 +9,8 @@ class PrimaryBtn extends StatelessWidget { final VoidCallback? onPressed; final bool bigMode; - const PrimaryBtn({Key? key, this.child, this.onPressed, this.bigMode = false}) : super(key: key); + const PrimaryBtn({Key? key, this.child, this.onPressed, this.bigMode = false}) + : super(key: key); @override Widget build(BuildContext context) { @@ -33,11 +34,17 @@ class PrimaryTextBtn extends StatelessWidget { final VoidCallback? onPressed; final bool bigMode; - const PrimaryTextBtn(this.label, {Key? key, this.onPressed, this.bigMode = false}) : super(key: key); + const PrimaryTextBtn(this.label, + {Key? key, this.onPressed, this.bigMode = false}) + : super(key: key); @override Widget build(BuildContext context) { - TextStyle txtStyle = (bigMode ? TextStyles.Callout : TextStyles.Footnote).textColor(Colors.white); - return PrimaryBtn(bigMode: bigMode, onPressed: onPressed, child: Text(label, style: txtStyle)); + TextStyle txtStyle = (bigMode ? TextStyles.Callout : TextStyles.Footnote) + .textColor(Colors.white); + return PrimaryBtn( + bigMode: bigMode, + onPressed: onPressed, + child: Text(label, style: txtStyle)); } } diff --git a/flokk_src/lib/styled_components/buttons/secondary_btn.dart b/flokk_src/lib/styled_components/buttons/secondary_btn.dart index 619be52..f8ff9c6 100644 --- a/flokk_src/lib/styled_components/buttons/secondary_btn.dart +++ b/flokk_src/lib/styled_components/buttons/secondary_btn.dart @@ -9,13 +9,15 @@ class SecondaryTextBtn extends StatelessWidget { final String label; final VoidCallback? onPressed; - const SecondaryTextBtn(this.label, {Key? key, this.onPressed}) : super(key: key); + const SecondaryTextBtn(this.label, {Key? key, this.onPressed}) + : super(key: key); @override Widget build(BuildContext context) { AppTheme theme = context.watch(); TextStyle txtStyle = TextStyles.Footnote.textColor(theme.accent1Darker); - return SecondaryBtn(onPressed: onPressed, child: Text(label, style: txtStyle)); + return SecondaryBtn( + onPressed: onPressed, child: Text(label, style: txtStyle)); } } @@ -78,7 +80,8 @@ class _SecondaryBtnState extends State { minHeight: widget.minHeight, contentPadding: EdgeInsets.all(widget.contentPadding), bgColor: theme.surface, - outlineColor: (_isMouseOver ? theme.accent1 : theme.grey).withOpacity(.35), + outlineColor: + (_isMouseOver ? theme.accent1 : theme.grey).withOpacity(.35), hoverColor: theme.surface, onFocusChanged: widget.onFocusChanged, downColor: theme.greyWeak.withOpacity(.35), diff --git a/flokk_src/lib/styled_components/buttons/transparent_btn.dart b/flokk_src/lib/styled_components/buttons/transparent_btn.dart index 6e88cff..ae393ae 100644 --- a/flokk_src/lib/styled_components/buttons/transparent_btn.dart +++ b/flokk_src/lib/styled_components/buttons/transparent_btn.dart @@ -41,7 +41,10 @@ class TransparentBtn extends StatelessWidget { vertical: bigMode ? Insets.sm : Insets.xs, ), bgColor: bgColor ?? Colors.transparent, - hoverColor: hoverColor ?? (theme.isDark ? ColorUtils.shiftHsl(theme.bg1, .2) : theme.bg2.withOpacity(.35)), + hoverColor: hoverColor ?? + (theme.isDark + ? ColorUtils.shiftHsl(theme.bg1, .2) + : theme.bg2.withOpacity(.35)), downColor: downColor ?? ColorUtils.shiftHsl(theme.bg2, .1), borderRadius: borderRadius, child: child, @@ -59,7 +62,12 @@ class TransparentTextBtn extends StatelessWidget { final Color? bgColor; const TransparentTextBtn(this.label, - {Key? key, this.onPressed, this.color, this.bigMode = false, this.style, this.bgColor}) + {Key? key, + this.onPressed, + this.color, + this.bigMode = false, + this.style, + this.bgColor}) : super(key: key); @override @@ -71,7 +79,11 @@ class TransparentTextBtn extends StatelessWidget { bgColor: bgColor, child: Row( mainAxisSize: MainAxisSize.min, - children: [Text(label, style: style ?? (bigMode ? TextStyles.Body1 : TextStyles.T1).textColor(c))], + children: [ + Text(label, + style: style ?? + (bigMode ? TextStyles.Body1 : TextStyles.T1).textColor(c)) + ], ), onPressed: onPressed, ); @@ -89,7 +101,13 @@ class TransparentIconAndTextBtn extends StatelessWidget { final TextStyle? style; const TransparentIconAndTextBtn(this.label, this.icon, - {Key? key, this.onPressed, this.color, this.textColor, this.bigMode = false, this.iconSize = 16, this.style}) + {Key? key, + this.onPressed, + this.color, + this.textColor, + this.bigMode = false, + this.iconSize = 16, + this.style}) : super(key: key); @override @@ -102,8 +120,10 @@ class TransparentIconAndTextBtn extends StatelessWidget { children: [ StyledImageIcon(icon, size: iconSize, color: c), HSpace(Insets.sm), - Text(label, style: style ?? TextStyles.Body1.textColor(textColor ?? c)), - HSpace(3), // Add a bit of extra padding to the right, seems like Icon() has it's own baked in padding + Text(label, + style: style ?? TextStyles.Body1.textColor(textColor ?? c)), + HSpace( + 3), // Add a bit of extra padding to the right, seems like Icon() has it's own baked in padding ], ), onPressed: onPressed, diff --git a/flokk_src/lib/styled_components/clickable_icon_row.dart b/flokk_src/lib/styled_components/clickable_icon_row.dart index e82f444..caabd13 100644 --- a/flokk_src/lib/styled_components/clickable_icon_row.dart +++ b/flokk_src/lib/styled_components/clickable_icon_row.dart @@ -45,13 +45,17 @@ class _ClickableIconRowState extends State { set isMouseOver(bool value) => setState(() => _isMouseOver = value); - void _handleEditPressed() => context.read().editSelectedContact(widget.editType); - void _handleCopyPressed() => Clipboard.setData(ClipboardData(text: widget.value)); + void _handleEditPressed() => + context.read().editSelectedContact(widget.editType); + void _handleCopyPressed() => + Clipboard.setData(ClipboardData(text: widget.value)); @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - Color overColor = theme.isDark ? ColorUtils.shiftHsl(theme.bg1, .2) : theme.bg2.withOpacity(.35); + Color overColor = theme.isDark + ? ColorUtils.shiftHsl(theme.bg1, .2) + : theme.bg2.withOpacity(.35); return MouseRegion( onEnter: (_) => isMouseOver = true, onExit: (_) => isMouseOver = false, @@ -68,14 +72,18 @@ class _ClickableIconRowState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.icon != null) - StyledImageIcon(widget.icon!, size: widget.size, color: widget.iconColor ?? theme.grey), + StyledImageIcon(widget.icon!, + size: widget.size, color: widget.iconColor ?? theme.grey), SizedBox(width: Insets.l), // Wrap value in ClickableText widget, it will get colored if anyone is listening //Text(value), - ClickableText(widget.value, onPressed: widget.onPressed).constrained(maxWidth: 300).flexible(), + ClickableText(widget.value, onPressed: widget.onPressed) + .constrained(maxWidth: 300) + .flexible(), SizedBox(width: Insets.m), if (widget.label != null) - Text(widget.label!.toUpperCase(), style: TextStyles.Caption.textColor(theme.greyWeak)) + Text(widget.label!.toUpperCase(), + style: TextStyles.Caption.textColor(theme.greyWeak)) .translate(offset: Offset(0, 8)), ], ).padding(right: Insets.l * 1.5), diff --git a/flokk_src/lib/styled_components/clickable_text.dart b/flokk_src/lib/styled_components/clickable_text.dart index 7e75ad3..477af41 100644 --- a/flokk_src/lib/styled_components/clickable_text.dart +++ b/flokk_src/lib/styled_components/clickable_text.dart @@ -13,7 +13,12 @@ class ClickableText extends StatelessWidget { final Color? linkColor; final bool underline; - const ClickableText(this.text, {Key? key, this.onPressed, this.style, this.underline = false, this.linkColor}) + const ClickableText(this.text, + {Key? key, + this.onPressed, + this.style, + this.underline = false, + this.linkColor}) : super(key: key); @override diff --git a/flokk_src/lib/styled_components/design_grid.dart b/flokk_src/lib/styled_components/design_grid.dart index 76ff42e..4452a28 100644 --- a/flokk_src/lib/styled_components/design_grid.dart +++ b/flokk_src/lib/styled_components/design_grid.dart @@ -7,7 +7,12 @@ class StyledDesignGrid extends StatelessWidget { final Alignment alignment; final bool isEnabled; - const StyledDesignGrid({Key? key, required this.child, this.alignment = Alignment.center, this.isEnabled = false}) : super(key: key); + const StyledDesignGrid( + {Key? key, + required this.child, + this.alignment = Alignment.center, + this.isEnabled = false}) + : super(key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/styled_components/flokk_logo.dart b/flokk_src/lib/styled_components/flokk_logo.dart index f2464bc..ecacb24 100644 --- a/flokk_src/lib/styled_components/flokk_logo.dart +++ b/flokk_src/lib/styled_components/flokk_logo.dart @@ -9,7 +9,8 @@ class FlokkLogo extends StatelessWidget { @override Widget build(BuildContext context) { - return Image.asset("assets/images/flokk-logo.png", color: color, height: size); + return Image.asset("assets/images/flokk-logo.png", + color: color, height: size); } } @@ -25,12 +26,14 @@ class FlokkSidebarLogo extends StatelessWidget { child: Stack( clipBehavior: Clip.none, children: [ - Image.asset("assets/images/sidebar-logo.png", width: skinny ? 140 : 160, filterQuality: FilterQuality.high), + Image.asset("assets/images/sidebar-logo.png", + width: skinny ? 140 : 160, filterQuality: FilterQuality.high), if (!skinny) ...{ Positioned( left: 160, top: 13, - child: Image.asset("assets/images/sidebar-bg.png", width: 84, filterQuality: FilterQuality.high), + child: Image.asset("assets/images/sidebar-bg.png", + width: 84, filterQuality: FilterQuality.high), ), }, ], diff --git a/flokk_src/lib/styled_components/opening_divider.dart b/flokk_src/lib/styled_components/opening_divider.dart index aca70d4..362bcce 100644 --- a/flokk_src/lib/styled_components/opening_divider.dart +++ b/flokk_src/lib/styled_components/opening_divider.dart @@ -8,7 +8,9 @@ class OpeningDivider extends StatelessWidget { final Color? openColor; final Color? closeColor; - const OpeningDivider({Key? key, this.isOpen = false, this.openColor, this.closeColor}) : super(key: key); + const OpeningDivider( + {Key? key, this.isOpen = false, this.openColor, this.closeColor}) + : super(key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/styled_components/scrolling/styled_horizontal_scroll_view.dart b/flokk_src/lib/styled_components/scrolling/styled_horizontal_scroll_view.dart index 59acedf..0481a78 100644 --- a/flokk_src/lib/styled_components/scrolling/styled_horizontal_scroll_view.dart +++ b/flokk_src/lib/styled_components/scrolling/styled_horizontal_scroll_view.dart @@ -6,14 +6,19 @@ class StyledHorizontalScrollView extends StatefulWidget { final Curve autoScrollCurve; final Widget? child; - StyledHorizontalScrollView({required this.autoScrollDuration, required this.autoScrollCurve, this.child, Key? key}) + StyledHorizontalScrollView( + {required this.autoScrollDuration, + required this.autoScrollCurve, + this.child, + Key? key}) : super(key: key); @override State createState() => _StyledHorizontalScrollViewState(); } -class _StyledHorizontalScrollViewState extends State { +class _StyledHorizontalScrollViewState + extends State { late GlobalKey _childContainerKey; late GlobalKey _scrollViewKey; double _childWidth = 0.0; @@ -62,8 +67,10 @@ class _StyledHorizontalScrollViewState extends State @override Widget build(BuildContext context) { /// Hook into these sub-widgets and rebuild once they callback with their current size - BuildUtils.getFutureSizeFromGlobalKey(_childContainerKey, (size) => childWidth = size.width); - BuildUtils.getFutureSizeFromGlobalKey(_scrollViewKey, (size) => scrollWidth = size.width); + BuildUtils.getFutureSizeFromGlobalKey( + _childContainerKey, (size) => childWidth = size.width); + BuildUtils.getFutureSizeFromGlobalKey( + _scrollViewKey, (size) => scrollWidth = size.width); return SingleChildScrollView( key: _scrollViewKey, diff --git a/flokk_src/lib/styled_components/scrolling/styled_listview.dart b/flokk_src/lib/styled_components/scrolling/styled_listview.dart index 32f2aef..994a6e4 100644 --- a/flokk_src/lib/styled_components/scrolling/styled_listview.dart +++ b/flokk_src/lib/styled_components/scrolling/styled_listview.dart @@ -60,7 +60,8 @@ class StyledListViewState extends State { @override void didUpdateWidget(StyledListView oldWidget) { - if (oldWidget.itemCount != widget.itemCount || oldWidget.itemExtent != widget.itemExtent) { + if (oldWidget.itemCount != widget.itemCount || + oldWidget.itemExtent != widget.itemExtent) { setState(() {}); } super.didUpdateWidget(oldWidget); @@ -95,7 +96,13 @@ class StyledListViewWithTitle extends StatelessWidget { final AssetImage? icon; final List listItems; - const StyledListViewWithTitle({Key? key, this.bgColor, this.title = "", this.listItems = const [], this.icon}) : super(key: key); + const StyledListViewWithTitle( + {Key? key, + this.bgColor, + this.title = "", + this.listItems = const [], + this.icon}) + : super(key: key); @override Widget build(BuildContext context) { @@ -115,7 +122,9 @@ class StyledListViewWithTitle extends StatelessWidget { ], ), VSpace(Insets.sm), - StyledListView(itemCount: listItems.length, itemBuilder: (_, i) => listItems[i]).flexible() + StyledListView( + itemCount: listItems.length, + itemBuilder: (_, i) => listItems[i]).flexible() ], ).padding(left: Insets.l * .75, right: Insets.m, vertical: Insets.m), ); diff --git a/flokk_src/lib/styled_components/scrolling/styled_scrollbar.dart b/flokk_src/lib/styled_components/scrolling/styled_scrollbar.dart index d16138e..a638fe6 100644 --- a/flokk_src/lib/styled_components/scrolling/styled_scrollbar.dart +++ b/flokk_src/lib/styled_components/scrolling/styled_scrollbar.dart @@ -92,7 +92,8 @@ class ScrollbarState extends State { double contentExtent = maxExtent + _viewExtent; // Calculate the alignment for the handle, this is a value between 0 and 1, // it automatically takes the handle size into acct - double handleAlignment = maxExtent == 0 ? 0 : widget.controller.offset / maxExtent; + double handleAlignment = + maxExtent == 0 ? 0 : widget.controller.offset / maxExtent; // Convert handle alignment from [0, 1] to [-1, 1] handleAlignment *= 2.0; @@ -107,10 +108,13 @@ class ScrollbarState extends State { // Hide the handle if content is < the viewExtent bool showHandle = contentExtent > _viewExtent && contentExtent > 0; // Handle color - Color handleColor = widget.handleColor ?? (theme.isDark ? theme.greyWeak.withOpacity(.2) : theme.greyWeak); + Color handleColor = widget.handleColor ?? + (theme.isDark ? theme.greyWeak.withOpacity(.2) : theme.greyWeak); // Track color - Color trackColor = - widget.trackColor ?? (theme.isDark ? theme.greyWeak.withOpacity(.1) : theme.greyWeak.withOpacity(.3)); + Color trackColor = widget.trackColor ?? + (theme.isDark + ? theme.greyWeak.withOpacity(.1) + : theme.greyWeak.withOpacity(.3)); //Layout the stack, it just contains a child, and return Stack(children: [ @@ -120,8 +124,12 @@ class ScrollbarState extends State { alignment: Alignment(1, 1), child: Container( color: trackColor, - width: widget.axis == Axis.vertical ? widget.size : double.infinity, - height: widget.axis == Axis.horizontal ? widget.size : double.infinity, + width: widget.axis == Axis.vertical + ? widget.size + : double.infinity, + height: widget.axis == Axis.horizontal + ? widget.size + : double.infinity, ), ), @@ -138,10 +146,14 @@ class ScrollbarState extends State { // HANDLE SHAPE child: MouseHoverBuilder( builder: (_, isHovered) => Container( - width: widget.axis == Axis.vertical ? widget.size : handleExtent, - height: widget.axis == Axis.horizontal ? widget.size : handleExtent, + width: + widget.axis == Axis.vertical ? widget.size : handleExtent, + height: widget.axis == Axis.horizontal + ? widget.size + : handleExtent, decoration: BoxDecoration( - color: handleColor.withOpacity(isHovered ? 1 : .85), borderRadius: Corners.s3Border), + color: handleColor.withOpacity(isHovered ? 1 : .85), + borderRadius: Corners.s3Border), ), ), ), @@ -153,15 +165,21 @@ class ScrollbarState extends State { void _handleHorizontalDrag(DragUpdateDetails details) { double pos = widget.controller.offset; - double pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) / _viewExtent; - widget.controller.jumpTo((pos + details.delta.dx * pxRatio).clamp(0.0, widget.controller.position.maxScrollExtent)); + double pxRatio = + (widget.controller.position.maxScrollExtent + _viewExtent) / + _viewExtent; + widget.controller.jumpTo((pos + details.delta.dx * pxRatio) + .clamp(0.0, widget.controller.position.maxScrollExtent)); widget.onDrag?.call(details.delta.dx); } void _handleVerticalDrag(DragUpdateDetails details) { double pos = widget.controller.offset; - double pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) / _viewExtent; - widget.controller.jumpTo((pos + details.delta.dy * pxRatio).clamp(0.0, widget.controller.position.maxScrollExtent)); + double pxRatio = + (widget.controller.position.maxScrollExtent + _viewExtent) / + _viewExtent; + widget.controller.jumpTo((pos + details.delta.dy * pxRatio) + .clamp(0.0, widget.controller.position.maxScrollExtent)); widget.onDrag?.call(details.delta.dy); } } diff --git a/flokk_src/lib/styled_components/scrolling/styled_scrollview.dart b/flokk_src/lib/styled_components/scrolling/styled_scrollview.dart index 03b3a20..3217ab0 100644 --- a/flokk_src/lib/styled_components/scrolling/styled_scrollview.dart +++ b/flokk_src/lib/styled_components/scrolling/styled_scrollview.dart @@ -15,7 +15,9 @@ class StyledScrollView extends StatefulWidget { Key? key, required this.child, this.contentSize, - this.axis = Axis.vertical, this.trackColor, this.handleColor, + this.axis = Axis.vertical, + this.trackColor, + this.handleColor, }) : super(key: key) {} @override diff --git a/flokk_src/lib/styled_components/social/clickable_social_badges.dart b/flokk_src/lib/styled_components/social/clickable_social_badges.dart index 7de2c9f..5501c87 100644 --- a/flokk_src/lib/styled_components/social/clickable_social_badges.dart +++ b/flokk_src/lib/styled_components/social/clickable_social_badges.dart @@ -25,7 +25,9 @@ class ClickableSocialBadges extends StatefulWidget { final ContactData contact; final bool showTimeSince; - const ClickableSocialBadges(this.contact, {Key? key, this.showTimeSince = false}) : super(key: key); + const ClickableSocialBadges(this.contact, + {Key? key, this.showTimeSince = false}) + : super(key: key); @override _ClickableSocialBadgesState createState() => _ClickableSocialBadgesState(); @@ -36,10 +38,13 @@ class _ClickableSocialBadgesState extends State { late Size _viewSize; - void _handleSocialClicked(BuildContext context, ContactData contact, SocialActivityType type) { + void _handleSocialClicked( + BuildContext context, ContactData contact, SocialActivityType type) { // If they clicked a badge that they have already entered a handle for, then open their social panel. if (contact.hasSocialOfType(type)) { - context.read().trySetSelectedContact(contact, showSocial: true); + context + .read() + .trySetSelectedContact(contact, showSocial: true); } else { _showSocialMiniFormOverlay(context, type); } @@ -63,7 +68,9 @@ class _ClickableSocialBadgesState extends State { // Figure out bottom text, changes if we have no social String bottomTxt = "Add Social IDs"; if (widget.contact.hasAnySocial) { - bottomTxt = lastSocialTime != Dates.epoch ? timeago.format(lastSocialTime) : "No New Activities"; + bottomTxt = lastSocialTime != Dates.epoch + ? timeago.format(lastSocialTime) + : "No New Activities"; } return LayoutBuilder( builder: (_, constraints) { @@ -81,7 +88,8 @@ class _ClickableSocialBadgesState extends State { iconPlaceholder: StyledIcons.twitterEmpty, newMessageCount: newTweets.length, hasAccount: widget.contact.hasTwitter, - onPressed: () => _handleSocialClicked(context, widget.contact, SocialActivityType.Twitter), + onPressed: () => _handleSocialClicked( + context, widget.contact, SocialActivityType.Twitter), ), HSpace(Insets.m), SocialBadge( @@ -89,12 +97,15 @@ class _ClickableSocialBadgesState extends State { iconPlaceholder: StyledIcons.githubEmpty, newMessageCount: newGits.length, hasAccount: widget.contact.hasGit, - onPressed: () => _handleSocialClicked(context, widget.contact, SocialActivityType.Git), + onPressed: () => _handleSocialClicked( + context, widget.contact, SocialActivityType.Git), ), ], ), if (widget.showTimeSince) VSpace(Insets.sm * 1.5), - if (widget.showTimeSince) Text(bottomTxt, style: TextStyles.Body2.textColor(theme.greyWeak)), + if (widget.showTimeSince) + Text(bottomTxt, + style: TextStyles.Body2.textColor(theme.greyWeak)), VSpace(Insets.sm), ]), ); @@ -102,7 +113,8 @@ class _ClickableSocialBadgesState extends State { ); } - void _showSocialMiniFormOverlay(BuildContext context, SocialActivityType type) { + void _showSocialMiniFormOverlay( + BuildContext context, SocialActivityType type) { AppTheme theme = context.read(); late OverlayEntry bg; late OverlayEntry form; @@ -115,13 +127,15 @@ class _ClickableSocialBadgesState extends State { bg = OverlayEntry( builder: (_) { return FadeInWidget( - Container(color: theme.greyWeak.withOpacity(.6)).gestures(onTap: _closeOverlay), + Container(color: theme.greyWeak.withOpacity(.6)) + .gestures(onTap: _closeOverlay), ); }, ); form = OverlayEntry(builder: (_) { return CompositedTransformFollower( - offset: Offset(-SocialPopupForm.kWidth * .5 + _viewSize.width * .5, 0), + offset: + Offset(-SocialPopupForm.kWidth * .5 + _viewSize.width * .5, 0), link: overlayLink, child: FadeInWidget(SocialPopupForm( widget.contact, diff --git a/flokk_src/lib/styled_components/social/git_item_renderer.dart b/flokk_src/lib/styled_components/social/git_item_renderer.dart index 8486e4e..fef99bc 100644 --- a/flokk_src/lib/styled_components/social/git_item_renderer.dart +++ b/flokk_src/lib/styled_components/social/git_item_renderer.dart @@ -36,7 +36,8 @@ class GitUtils { if (type == "GistEvent") return "Gist"; if (type == "GollumEvent") return "Gollum"; if (type == "InstallationEvent") return "Installation"; - if (type == "InstallationRepositoriesEvent") return "Installation Repositories"; + if (type == "InstallationRepositoriesEvent") + return "Installation Repositories"; if (type == "IssueCommentEvent") return "Commented on Issue"; if (type == "IssuesEvent") return "Issues"; if (type == "LabelEvent") return "Labelled"; @@ -55,13 +56,15 @@ class GitUtils { if (type == "PublicEvent") return "Public"; if (type == "PullRequestEvent") return "Pull Requested"; if (type == "PullRequestReviewEvent") return "Reviewed Pull Request"; - if (type == "PullRequestReviewCommentEvent") return "Commented Pull Request Review"; + if (type == "PullRequestReviewCommentEvent") + return "Commented Pull Request Review"; if (type == "PushEvent") return "Pushed"; if (type == "ReleaseEvent") return "Released"; if (type == "RepositoryDispatchEvent") return "Repository Dispatch"; if (type == "RepositoryEvent") return "Repository"; if (type == "RepositoryImportEvent") return "Repository Import"; - if (type == "RepositoryVulnerabilityAlertEvent") return "Repository Vulnerability Alert"; + if (type == "RepositoryVulnerabilityAlertEvent") + return "Repository Vulnerability Alert"; if (type == "SecurityAdvisoryEvent") return "Security Advisory"; if (type == "SponsorshipEvent") return "Sponsorship"; if (type == "StarEvent") return "Starred"; @@ -111,7 +114,9 @@ class GitRepoListItem extends StatelessWidget { children: [ Row(children: [ Text("${repo.contacts.first.nameGiven}", style: titleStyle.bold), - Text(" · ${GitUtils.monthDayFmt.format(repo.repository.updatedAt ?? Dates.epoch)}", style: titleStyle), + Text( + " · ${GitUtils.monthDayFmt.format(repo.repository.updatedAt ?? Dates.epoch)}", + style: titleStyle), ]), VSpace(Insets.xs * 1.5), GitRepoInfo(repo.repository), @@ -143,8 +148,7 @@ class GitRepoInfo extends StatelessWidget { const GitRepoInfo(this.repo, {Key? key}) : super(key: key); void _handleRepoPressed() { - if (repo != null) - UrlLauncher.openHttp(repo!.htmlUrl); + if (repo != null) UrlLauncher.openHttp(repo!.htmlUrl); } @override @@ -158,8 +162,12 @@ class GitRepoInfo extends StatelessWidget { RichText( text: TextSpan( children: [ - TextSpan(text: "${repo?.name}", style: contentTextStyle.textColor(theme.accent1Dark)), - TextSpan(text: " | ${repo?.description}", style: contentTextStyle.textColor(theme.txt)), + TextSpan( + text: "${repo?.name}", + style: contentTextStyle.textColor(theme.accent1Dark)), + TextSpan( + text: " | ${repo?.description}", + style: contentTextStyle.textColor(theme.txt)), ], ), ).flexible(), @@ -172,15 +180,22 @@ class GitRepoInfo extends StatelessWidget { HSpace(Insets.sm), }, StyledImageIcon(StyledIcons.starFilled, size: 12, color: theme.grey), - Text("${repo?.stargazersCount ?? 0}", style: smallTextStyle).padding(left: Insets.xs), + Text("${repo?.stargazersCount ?? 0}", style: smallTextStyle) + .padding(left: Insets.xs), HSpace(Insets.sm), - StyledImageIcon(StyledIcons.socialFork, size: 12, color: theme.grey).translate( - offset: Offset(0, 1), // Add a bit of offset to the fork icon cause it's a bit tall and doesn't look right + StyledImageIcon(StyledIcons.socialFork, size: 12, color: theme.grey) + .translate( + offset: Offset(0, + 1), // Add a bit of offset to the fork icon cause it's a bit tall and doesn't look right ), - Text("${repo?.forksCount ?? 0}", style: smallTextStyle).padding(left: Insets.xs), + Text("${repo?.forksCount ?? 0}", style: smallTextStyle) + .padding(left: Insets.xs), ]), VSpace(Insets.m * 1.5), - Container(color: theme.greyWeak.withOpacity(.35), width: double.infinity, height: 1), + Container( + color: theme.greyWeak.withOpacity(.35), + width: double.infinity, + height: 1), //VSpace(Insets.l), ], ).gestures(onTap: _handleRepoPressed); diff --git a/flokk_src/lib/styled_components/social/social_badge.dart b/flokk_src/lib/styled_components/social/social_badge.dart index f312dfb..aa08519 100644 --- a/flokk_src/lib/styled_components/social/social_badge.dart +++ b/flokk_src/lib/styled_components/social/social_badge.dart @@ -34,10 +34,16 @@ class SocialBadge extends StatelessWidget { child: Stack( children: [ /// PLACEHOLDER - if (!hasAccount) StyledImageIcon(iconPlaceholder, size: 32, color: theme.greyWeak.withOpacity(.7)).center(), + if (!hasAccount) + StyledImageIcon(iconPlaceholder, + size: 32, color: theme.greyWeak.withOpacity(.7)) + .center(), /// VALID ACCOUNT - if (hasAccount) StyledImageIcon(icon, size: 28, color: newMessageCount > 0 ? theme.accent1 : theme.grey), + if (hasAccount) + StyledImageIcon(icon, + size: 28, + color: newMessageCount > 0 ? theme.accent1 : theme.grey), if (hasAccount) StyledContainer( theme.bg1, @@ -48,7 +54,9 @@ class SocialBadge extends StatelessWidget { textAlign: TextAlign.center, style: TextStyles.Footnote.textColor(theme.txt).letterSpace(1), ).translate(offset: Offset(0, -1)), - ).constrained(width: 19, height: 19).alignment(Alignment.bottomRight), + ) + .constrained(width: 19, height: 19) + .alignment(Alignment.bottomRight), ], ).width(size).height(size), ); diff --git a/flokk_src/lib/styled_components/social/social_popup_form.dart b/flokk_src/lib/styled_components/social/social_popup_form.dart index 545fb4f..e0d28d7 100644 --- a/flokk_src/lib/styled_components/social/social_popup_form.dart +++ b/flokk_src/lib/styled_components/social/social_popup_form.dart @@ -26,7 +26,8 @@ class SocialPopupForm extends StatefulWidget { final ContactData contact; final SocialActivityType socialActivityType; - const SocialPopupForm(this.contact, {Key? key, this.onClosePressed, required this.socialActivityType}) + const SocialPopupForm(this.contact, + {Key? key, this.onClosePressed, required this.socialActivityType}) : super(key: key); @override @@ -69,7 +70,8 @@ class _SocialPopupFormState extends State { hint: "github.com/", initial: widget.contact.gitUsername, onChanged: _handleGitChanged, - autoFocus: widget.socialActivityType == SocialActivityType.Git, + autoFocus: + widget.socialActivityType == SocialActivityType.Git, ), VSpace(Insets.sm), @@ -79,16 +81,19 @@ class _SocialPopupFormState extends State { hint: "@", initial: widget.contact.twitterHandle, onChanged: _handleTwitterChanged, - autoFocus: widget.socialActivityType == SocialActivityType.Twitter, + autoFocus: + widget.socialActivityType == SocialActivityType.Twitter, ), VSpace(Insets.l), /// SUBMIT BUTTONS Row( children: [ - PrimaryTextBtn("SAVE", onPressed: () => _handleBtnPressed(true)), + PrimaryTextBtn("SAVE", + onPressed: () => _handleBtnPressed(true)), HSpace(Insets.m), - SecondaryTextBtn("CANCEL", onPressed: () => _handleBtnPressed(false)), + SecondaryTextBtn("CANCEL", + onPressed: () => _handleBtnPressed(false)), ], ), ], @@ -108,30 +113,44 @@ class _SocialTextInput extends StatelessWidget { final void Function(String) onChanged; const _SocialTextInput( - {Key? key, this.hint = "", required this.onChanged, this.initial = "", required this.icon, this.autoFocus = false}) + {Key? key, + this.hint = "", + required this.onChanged, + this.initial = "", + required this.icon, + this.autoFocus = false}) : super(key: key); @override Widget build(BuildContext context) { AppTheme theme = context.watch(); double prefixSize = StringUtils.measure(hint, TextStyles.Body1).width; - EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding.copyWith(left: prefixSize + .5); + EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding + .copyWith(left: prefixSize + .5); return Row( mainAxisSize: MainAxisSize.min, children: [ - StyledImageIcon(icon, color: ColorUtils.shiftHsl(theme.accent1, theme.isDark ? .2 : -.2), size: 30), + StyledImageIcon(icon, + color: ColorUtils.shiftHsl(theme.accent1, theme.isDark ? .2 : -.2), + size: 30), HSpace(Insets.m), Stack( children: [ /// Prefix text, non-interactive FocusScope( canRequestFocus: false, - child: IgnorePointer(child: buildTextInput(context, hint: hint, onChanged: (v) {}))), + child: IgnorePointer( + child: buildTextInput(context, + hint: hint, onChanged: (v) {}))), /// Value text buildTextInput(context, - hint: "", initial: initial, onChanged: onChanged, autoFocus: autoFocus, padding: padding), + hint: "", + initial: initial, + onChanged: onChanged, + autoFocus: autoFocus, + padding: padding), ], ).flexible() ], @@ -139,7 +158,11 @@ class _SocialTextInput extends StatelessWidget { } buildTextInput(BuildContext context, - {String hint = "", String initial = "", bool autoFocus = false, void Function(String)? onChanged, EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding}) { + {String hint = "", + String initial = "", + bool autoFocus = false, + void Function(String)? onChanged, + EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding}) { return StyledFormTextInput( contentPadding: padding, hintText: hint, diff --git a/flokk_src/lib/styled_components/social/tweet_item_renderer.dart b/flokk_src/lib/styled_components/social/tweet_item_renderer.dart index bed8188..3f32dcf 100644 --- a/flokk_src/lib/styled_components/social/tweet_item_renderer.dart +++ b/flokk_src/lib/styled_components/social/tweet_item_renderer.dart @@ -25,7 +25,8 @@ class TweetListItem extends StatelessWidget { Widget build(BuildContext context) { AppTheme theme = context.watch(); int minutesAgo = DateTime.now().difference(tweet.createdAt).inMinutes; - String timeTxt = minutesAgo < 60 ? "${minutesAgo}m" : "${(minutesAgo / 60).round()}h"; + String timeTxt = + minutesAgo < 60 ? "${minutesAgo}m" : "${(minutesAgo / 60).round()}h"; if (minutesAgo > 60 * 24) { timeTxt = "${(minutesAgo / 60 / 24).round()}d"; } @@ -35,7 +36,9 @@ class TweetListItem extends StatelessWidget { Row(children: [ OneLineText(tweet.user.name, style: titleStyle.bold).flexible(), HSpace(Insets.sm), - OneLineText(tweet.retweeted ? "Retweeted" : "Tweeted", style: titleStyle).flexible(), + OneLineText(tweet.retweeted ? "Retweeted" : "Tweeted", + style: titleStyle) + .flexible(), Text(" · ", style: titleStyle), Text(timeTxt, style: titleStyle), ]), @@ -43,8 +46,10 @@ class TweetListItem extends StatelessWidget { Row(children: [ SelectableLinkText( text: "${tweet.text}", - linkStyle: TextStyles.Body1.textHeight(1.6).textColor(theme.accent1), - textStyle: TextStyles.Body1.textHeight(1.6).textColor(theme.txt)) + linkStyle: + TextStyles.Body1.textHeight(1.6).textColor(theme.accent1), + textStyle: + TextStyles.Body1.textHeight(1.6).textColor(theme.txt)) .flexible() ]), VSpace(Insets.m), @@ -56,7 +61,8 @@ class TweetListItem extends StatelessWidget { style: TextStyles.Body3.textColor(theme.grey), ), HSpace(Insets.m), - StyledImageIcon(StyledIcons.socialRetweet, size: 12, color: theme.grey), + StyledImageIcon(StyledIcons.socialRetweet, + size: 12, color: theme.grey), HSpace(Insets.sm), Text( "${tweet.retweetCount}", @@ -64,10 +70,12 @@ class TweetListItem extends StatelessWidget { ), ]), VSpace(Insets.m), - Container(color: theme.greyWeak.withOpacity(.35), width: double.infinity, height: 1), + Container( + color: theme.greyWeak.withOpacity(.35), + width: double.infinity, + height: 1), VSpace(Insets.l), ], ).gestures(onTap: _handleRowPressed, behavior: HitTestBehavior.opaque); } - } diff --git a/flokk_src/lib/styled_components/styled_autocomplete_dropdown.dart b/flokk_src/lib/styled_components/styled_autocomplete_dropdown.dart index 0381bb1..ad66968 100644 --- a/flokk_src/lib/styled_components/styled_autocomplete_dropdown.dart +++ b/flokk_src/lib/styled_components/styled_autocomplete_dropdown.dart @@ -22,14 +22,22 @@ class StyledAutoCompleteDropdown extends StatefulWidget { final void Function(bool)? onFocusChanged; const StyledAutoCompleteDropdown( - {Key? key, this.initialValue, this.hint = "", this.items = const[], this.onChanged, this.onFocusChanged, this.maxHeight = 500}) + {Key? key, + this.initialValue, + this.hint = "", + this.items = const [], + this.onChanged, + this.onFocusChanged, + this.maxHeight = 500}) : super(key: key); @override - _StyledAutoCompleteDropdownState createState() => _StyledAutoCompleteDropdownState(); + _StyledAutoCompleteDropdownState createState() => + _StyledAutoCompleteDropdownState(); } -class _StyledAutoCompleteDropdownState extends State { +class _StyledAutoCompleteDropdownState + extends State { bool _isOpen = false; OverlayEntry? _overlay; late ValueNotifier> _itemsFiltered; @@ -62,7 +70,9 @@ class _StyledAutoCompleteDropdownState extends State } void _updateFilteredItems() { - _itemsFiltered.value = widget.items.where((i) => i.contains(currentText.toUpperCase())).toList(); + _itemsFiltered.value = widget.items + .where((i) => i.contains(currentText.toUpperCase())) + .toList(); } void _handleArrowTap() { @@ -77,12 +87,14 @@ class _StyledAutoCompleteDropdownState extends State void _handleRawKeyPressed(RawKeyEvent evt) { if (evt is RawKeyDownEvent) { - if ((_textFocusNode?.hasFocus ?? false) && evt.logicalKey == LogicalKeyboardKey.arrowDown) { + if ((_textFocusNode?.hasFocus ?? false) && + evt.logicalKey == LogicalKeyboardKey.arrowDown) { _skipNextFocusOut = true; Future.microtask(() => _dropDownFocusNode.requestFocus()); } if (_dropDownFocusNode.hasFocus && - (evt.logicalKey == LogicalKeyboardKey.arrowRight || evt.logicalKey == LogicalKeyboardKey.arrowLeft)) { + (evt.logicalKey == LogicalKeyboardKey.arrowRight || + evt.logicalKey == LogicalKeyboardKey.arrowLeft)) { _textFocusNode?.requestFocus(); } } @@ -137,7 +149,8 @@ class _StyledAutoCompleteDropdownState extends State onFocusCreated: _handleFocusCreate, onFocusChanged: _handleFocusChanged, onChanged: _handleValueChanged), - StyledImageIcon(StyledIcons.dropdownClose, size: 12, color: theme.greyStrong) + StyledImageIcon(StyledIcons.dropdownClose, + size: 12, color: theme.greyStrong) .rotate(angle: downArrow ? 0 : pi, animate: true) .animate(Durations.fast, Curves.easeOut) .alignment(Alignment.topLeft) @@ -150,7 +163,9 @@ class _StyledAutoCompleteDropdownState extends State void showOverlay([bool show = true]) { if (show && _overlay == null) { - final overlay = OverlayEntry(builder: (_) => _AutoCompleteDropdown(this, focusNode: _dropDownFocusNode)); + final overlay = OverlayEntry( + builder: (_) => + _AutoCompleteDropdown(this, focusNode: _dropDownFocusNode)); _overlay = overlay; Overlay.of(context)?.insert(overlay); } else if (!show && _overlay != null) { @@ -172,7 +187,9 @@ class _AutoCompleteDropdown extends StatelessWidget { final double rowHeight; final FocusScopeNode? focusNode; - _AutoCompleteDropdown(this.state, {Key? key, this.focusNode, this.rowHeight = 40}) : super(key: key); + _AutoCompleteDropdown(this.state, + {Key? key, this.focusNode, this.rowHeight = 40}) + : super(key: key); List get items => state.widget.items; @@ -184,7 +201,8 @@ class _AutoCompleteDropdown extends StatelessWidget { RenderBox? rb = state.context.findRenderObject() as RenderBox?; if (rb == null) return Container(); Size size = rb.size; - double longest = StringUtils.measureLongest(filteredItems, TextStyles.Caption, 50); + double longest = + StringUtils.measureLongest(filteredItems, TextStyles.Caption, 50); longest += Insets.m * 2; double maxHeight = state.widget.maxHeight; @@ -207,9 +225,11 @@ class _AutoCompleteDropdown extends StatelessWidget { itemCount: matches.length, itemBuilder: (_, index) { return BaseStyledBtn( - contentPadding: EdgeInsets.symmetric(horizontal: Insets.m), + contentPadding: + EdgeInsets.symmetric(horizontal: Insets.m), minHeight: rowHeight, - onPressed: () => state._handleItemSelected(matches[index]), + onPressed: () => + state._handleItemSelected(matches[index]), child: OneLineText( "${matches[index].toUpperCase()}", style: TextStyles.Caption.textColor(theme.greyWeak), @@ -217,8 +237,12 @@ class _AutoCompleteDropdown extends StatelessWidget { ); }, ) - .decorated(color: theme.surface, boxShadow: Shadows.m(theme.accent1)) - .constrained(width: max(longest, size.width), height: min(matches.length * rowHeight, maxHeight)) + .decorated( + color: theme.surface, + boxShadow: Shadows.m(theme.accent1)) + .constrained( + width: max(longest, size.width), + height: min(matches.length * rowHeight, maxHeight)) .padding(top: 26) //.positioned(left: pos.dx, top: pos.dy) ], diff --git a/flokk_src/lib/styled_components/styled_card.dart b/flokk_src/lib/styled_components/styled_card.dart index 3654e29..1154763 100644 --- a/flokk_src/lib/styled_components/styled_card.dart +++ b/flokk_src/lib/styled_components/styled_card.dart @@ -13,7 +13,13 @@ class StyledCard extends StatelessWidget { final VoidCallback? onPressed; final Alignment? align; - const StyledCard({Key? key, this.bgColor, this.enableShadow = true, this.child, this.onPressed, this.align}) + const StyledCard( + {Key? key, + this.bgColor, + this.enableShadow = true, + this.child, + this.onPressed, + this.align}) : super(key: key); @override @@ -27,7 +33,8 @@ class StyledCard extends StatelessWidget { borderRadius: Corners.s8Border, shadows: enableShadow ? Shadows.m(theme.accent1Darker) : null); - if (onPressed != null) return TransparentBtn(child: content, onPressed: onPressed); + if (onPressed != null) + return TransparentBtn(child: content, onPressed: onPressed); return content; } } diff --git a/flokk_src/lib/styled_components/styled_checkbox.dart b/flokk_src/lib/styled_components/styled_checkbox.dart index 4af512c..2a91ac1 100644 --- a/flokk_src/lib/styled_components/styled_checkbox.dart +++ b/flokk_src/lib/styled_components/styled_checkbox.dart @@ -17,7 +17,11 @@ class StyledCheckbox extends StatelessWidget { final double size; final void Function(StyledCheckboxValue)? onChanged; - const StyledCheckbox({Key? key, this.value = StyledCheckboxValue.None, this.size = 18, this.onChanged}) + const StyledCheckbox( + {Key? key, + this.value = StyledCheckboxValue.None, + this.size = 18, + this.onChanged}) : super(key: key); void _handleTapUp(TapUpDetails details) { @@ -37,17 +41,20 @@ class StyledCheckbox extends StatelessWidget { Widget _getIconForCurrentState() { switch (value) { case StyledCheckboxValue.All: - return StyledImageIcon(StyledIcons.checkboxSelected, color: Colors.white, size: 15); + return StyledImageIcon(StyledIcons.checkboxSelected, + color: Colors.white, size: 15); case StyledCheckboxValue.None: return Container(); case StyledCheckboxValue.Partial: - return StyledImageIcon(StyledIcons.checkboxPartial, color: Colors.white, size: 15); + return StyledImageIcon(StyledIcons.checkboxPartial, + color: Colors.white, size: 15); } } Widget _wrapGestures(Widget child) { if (onChanged == null) return child; - return child.gestures(onTapUp: _handleTapUp, behavior: HitTestBehavior.opaque); + return child.gestures( + onTapUp: _handleTapUp, behavior: HitTestBehavior.opaque); } @override @@ -57,9 +64,15 @@ class StyledCheckbox extends StatelessWidget { width: size, height: size, decoration: BoxDecoration( - color: value == StyledCheckboxValue.None ? Colors.transparent : theme.accent1Darker, + color: value == StyledCheckboxValue.None + ? Colors.transparent + : theme.accent1Darker, borderRadius: Corners.s3Border, - border: Border.all(color: value == StyledCheckboxValue.None ? theme.grey : theme.accent1Darker, width: 1.5)), + border: Border.all( + color: value == StyledCheckboxValue.None + ? theme.grey + : theme.accent1Darker, + width: 1.5)), child: _wrapGestures(_getIconForCurrentState()), ); } diff --git a/flokk_src/lib/styled_components/styled_container.dart b/flokk_src/lib/styled_components/styled_container.dart index 26d6118..d071591 100644 --- a/flokk_src/lib/styled_components/styled_container.dart +++ b/flokk_src/lib/styled_components/styled_container.dart @@ -37,6 +37,9 @@ class StyledContainer extends StatelessWidget { alignment: align, duration: duration, decoration: BoxDecoration( - color: color, borderRadius: borderRadius, boxShadow: shadows, border: border)); + color: color, + borderRadius: borderRadius, + boxShadow: shadows, + border: border)); } } diff --git a/flokk_src/lib/styled_components/styled_dialogs.dart b/flokk_src/lib/styled_components/styled_dialogs.dart index 0fca1f8..76c5eef 100644 --- a/flokk_src/lib/styled_components/styled_dialogs.dart +++ b/flokk_src/lib/styled_components/styled_dialogs.dart @@ -9,9 +9,11 @@ import 'package:provider/provider.dart'; class Dialogs { static Future show(Widget child, [BuildContext? context]) async { - return await (context != null ? Navigator.of(context) : AppGlobals.nav)?.push( + return await (context != null ? Navigator.of(context) : AppGlobals.nav) + ?.push( StyledDialogRoute( - pageBuilder: (BuildContext buildContext, Animation animation, Animation secondaryAnimation) { + pageBuilder: (BuildContext buildContext, Animation animation, + Animation secondaryAnimation) { return SafeArea(child: child); }, ), @@ -56,7 +58,8 @@ class StyledDialog extends StatelessWidget { ); if (shrinkWrap) { - innerContent = IntrinsicWidth(child: IntrinsicHeight(child: innerContent)); + innerContent = + IntrinsicWidth(child: IntrinsicHeight(child: innerContent)); } return FocusTraversalGroup( @@ -73,7 +76,8 @@ class StyledDialog extends StatelessWidget { borderRadius: borderRadius, child: SingleChildScrollView( physics: StyledScrollPhysics(), - child: Material(type: MaterialType.transparency, child: innerContent), + child: Material( + type: MaterialType.transparency, child: innerContent), ), ), ), @@ -112,7 +116,8 @@ class OkCancelDialog extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (titleStr != null) ...[ - Text(titleStr.toUpperCase(), style: TextStyles.T1.textColor(theme.accent1Darker)), + Text(titleStr.toUpperCase(), + style: TextStyles.T1.textColor(theme.accent1Darker)), VSpace(Insets.sm * 1.5), Container(color: theme.greyWeak.withOpacity(.35), height: 1), VSpace(Insets.m * 1.5), @@ -169,7 +174,8 @@ class StyledDialogRoute extends PopupRoute { final RouteTransitionsBuilder? _transitionBuilder; @override - Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { return Semantics( child: _pageBuilder(context, animation, secondaryAnimation), scopesRoute: true, @@ -178,11 +184,13 @@ class StyledDialogRoute extends PopupRoute { } @override - Widget buildTransitions( - BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + Widget buildTransitions(BuildContext context, Animation animation, + Animation secondaryAnimation, Widget child) { RouteTransitionsBuilder? tb = _transitionBuilder; if (tb == null) { - return FadeTransition(opacity: CurvedAnimation(parent: animation, curve: Curves.linear), child: child); + return FadeTransition( + opacity: CurvedAnimation(parent: animation, curve: Curves.linear), + child: child); } // Some default transition return tb(context, animation, secondaryAnimation, child); } diff --git a/flokk_src/lib/styled_components/styled_form_label_input.dart b/flokk_src/lib/styled_components/styled_form_label_input.dart index bee9d16..1d742a0 100644 --- a/flokk_src/lib/styled_components/styled_form_label_input.dart +++ b/flokk_src/lib/styled_components/styled_form_label_input.dart @@ -13,7 +13,8 @@ import 'package:provider/provider.dart'; class StyledFormLabelInput extends StatefulWidget { //TODO SB@CE - Is this necessary, can't we just pass null and let the default inside StyledSearchTextInput handle it? - static const EdgeInsets kDefaultTextInputPadding = EdgeInsets.only(bottom: Insets.sm, top: 4); + static const EdgeInsets kDefaultTextInputPadding = + EdgeInsets.only(bottom: Insets.sm, top: 4); final String hintText; final bool autoFocus; @@ -95,8 +96,10 @@ class _StyledFormLabelInputState extends State { void _handleRawKeyPressed(RawKeyEvent evt) { if (evt is RawKeyDownEvent) { - if ((_textFocusNode?.hasFocus ?? false) && evt.logicalKey == LogicalKeyboardKey.backspace) { - if (_textKey.currentState != null && (_textKey.currentState?.text.isEmpty ?? false)) { + if ((_textFocusNode?.hasFocus ?? false) && + evt.logicalKey == LogicalKeyboardKey.backspace) { + if (_textKey.currentState != null && + (_textKey.currentState?.text.isEmpty ?? false)) { final tl = widget.labels; if (tl.isNotEmpty) { _handleRemoveLabel(tl.last); @@ -114,7 +117,9 @@ class _StyledFormLabelInputState extends State { //TODO SB@CE - This could be more readable final labelWidth = (String label) { return Insets.m + - StringUtils.measure(label.toUpperCase(), TextStyles.Footnote.letterSpace(0)).width + + StringUtils.measure( + label.toUpperCase(), TextStyles.Footnote.letterSpace(0)) + .width + Insets.sm + Insets.sm + 16 + @@ -165,7 +170,9 @@ class _StyledFormLabelInputState extends State { Container( margin: EdgeInsets.only(top: 38), height: _focused ? 1.8 : 1.2, - color: _focused ? (theme.isDark ? theme.accent2 : theme.accent1Dark) : theme.greyWeak.withOpacity(.35), + color: _focused + ? (theme.isDark ? theme.accent2 : theme.accent1Dark) + : theme.greyWeak.withOpacity(.35), ) ], ), diff --git a/flokk_src/lib/styled_components/styled_group_label.dart b/flokk_src/lib/styled_components/styled_group_label.dart index a8df999..0f2ecc1 100644 --- a/flokk_src/lib/styled_components/styled_group_label.dart +++ b/flokk_src/lib/styled_components/styled_group_label.dart @@ -18,7 +18,12 @@ class StyledGroupLabel extends StatelessWidget { final VoidCallback? onClose; final VoidCallback? onPressed; - StyledGroupLabel({this.icon, this.text = "", this.onFocusChanged, this.onClose, this.onPressed}) + StyledGroupLabel( + {this.icon, + this.text = "", + this.onFocusChanged, + this.onClose, + this.onPressed}) : assert(icon == null || (icon is AssetImage) || (icon is IconData)); @override @@ -37,14 +42,15 @@ class StyledGroupLabel extends StatelessWidget { color: theme.accent1Darker, ), }, - Text(text.toUpperCase(), style: TextStyles.Footnote.letterSpace(0).textColor(theme.grey)) + Text(text.toUpperCase(), + style: TextStyles.Footnote.letterSpace(0).textColor(theme.grey)) .padding(left: Insets.m), if (onClose != null) ...{ ColorShiftIconBtn( StyledIcons.closeLarge, minWidth: 0, minHeight: 0, - // 8 padding on either side + 8 icon size = design dimensions, minWidth doesn't seem to work for this so I'm using padding instead + // 8 padding on either side + 8 icon size = design dimensions, minWidth doesn't seem to work for this so I'm using padding instead padding: EdgeInsets.all(8), size: 8, color: theme.grey, @@ -52,7 +58,7 @@ class StyledGroupLabel extends StatelessWidget { onFocusChanged: onFocusChanged, onPressed: onClose, ), - } else ... { + } else ...{ HSpace(Insets.m), }, ], @@ -70,7 +76,9 @@ class StyledGroupLabel extends StatelessWidget { ) : Container( height: 30, - decoration: BoxDecoration(borderRadius: Corners.s5Border, color: theme.bg2.withOpacity(.35)), + decoration: BoxDecoration( + borderRadius: Corners.s5Border, + color: theme.bg2.withOpacity(.35)), child: content, ); } diff --git a/flokk_src/lib/styled_components/styled_icons.dart b/flokk_src/lib/styled_components/styled_icons.dart index 94e67d9..069e3f6 100644 --- a/flokk_src/lib/styled_components/styled_icons.dart +++ b/flokk_src/lib/styled_components/styled_icons.dart @@ -5,41 +5,55 @@ class StyledIcons { static AssetImage get address => AssetImage("assets/icons/icon-address.png"); - static AssetImage get birthday => AssetImage("assets/icons/icon-birthday.png"); + static AssetImage get birthday => + AssetImage("assets/icons/icon-birthday.png"); - static AssetImage get calendar => AssetImage("assets/icons/icon-calendar.png"); + static AssetImage get calendar => + AssetImage("assets/icons/icon-calendar.png"); - static AssetImage get checkboxPartial => AssetImage("assets/icons/icon-checkbox-partial.png"); + static AssetImage get checkboxPartial => + AssetImage("assets/icons/icon-checkbox-partial.png"); - static AssetImage get checkboxSelected => AssetImage("assets/icons/icon-checkbox-selected.png"); + static AssetImage get checkboxSelected => + AssetImage("assets/icons/icon-checkbox-selected.png"); - static AssetImage get closeLarge => AssetImage("assets/icons/icon-close-large.png"); + static AssetImage get closeLarge => + AssetImage("assets/icons/icon-close-large.png"); static AssetImage get copy => AssetImage("assets/icons/icon-copy.png"); - static AssetImage get darkMode => AssetImage("assets/icons/icon-darkmode.png"); + static AssetImage get darkMode => + AssetImage("assets/icons/icon-darkmode.png"); - static AssetImage get dashboard => AssetImage("assets/icons/icon-dashboard.png"); + static AssetImage get dashboard => + AssetImage("assets/icons/icon-dashboard.png"); - static AssetImage get dropdownClose => AssetImage("assets/icons/icon-dropdown-close.png"); + static AssetImage get dropdownClose => + AssetImage("assets/icons/icon-dropdown-close.png"); - static AssetImage get dropdownOpen => AssetImage("assets/icons/icon-dropdown-open.png"); + static AssetImage get dropdownOpen => + AssetImage("assets/icons/icon-dropdown-open.png"); static AssetImage get edit => AssetImage("assets/icons/icon-edit.png"); static AssetImage get formAdd => AssetImage("assets/icons/icon-form-add.png"); - static AssetImage get formAddLabel => AssetImage("assets/icons/icon-form-add-label.png"); + static AssetImage get formAddLabel => + AssetImage("assets/icons/icon-form-add-label.png"); - static AssetImage get formDelete => AssetImage("assets/icons/icon-form-delete.png"); + static AssetImage get formDelete => + AssetImage("assets/icons/icon-form-delete.png"); - static AssetImage get githubActive => AssetImage("assets/icons/icon-github-active.png"); + static AssetImage get githubActive => + AssetImage("assets/icons/icon-github-active.png"); - static AssetImage get githubEmpty => AssetImage("assets/icons/icon-github-empty.png"); + static AssetImage get githubEmpty => + AssetImage("assets/icons/icon-github-empty.png"); static AssetImage get label => AssetImage("assets/icons/icon-label.png"); - static AssetImage get lightMode => AssetImage("assets/icons/icon-lightmode.png"); + static AssetImage get lightMode => + AssetImage("assets/icons/icon-lightmode.png"); static AssetImage get link => AssetImage("assets/icons/icon-link.png"); @@ -53,11 +67,13 @@ class StyledIcons { static AssetImage get phone => AssetImage("assets/icons/icon-phone.png"); - static AssetImage get previous => AssetImage("assets/icons/icon-previous.png"); + static AssetImage get previous => + AssetImage("assets/icons/icon-previous.png"); static AssetImage get refresh => AssetImage("assets/icons/icon-refresh.png"); - static AssetImage get relationship => AssetImage("assets/icons/icon-relationship.png"); + static AssetImage get relationship => + AssetImage("assets/icons/icon-relationship.png"); static AssetImage get save => AssetImage("assets/icons/icon-save.png"); @@ -67,23 +83,31 @@ class StyledIcons { static AssetImage get signOut => AssetImage("assets/icons/icon-signout.png"); - static AssetImage get socialFork => AssetImage("assets/icons/icon-social-fork.png"); + static AssetImage get socialFork => + AssetImage("assets/icons/icon-social-fork.png"); - static AssetImage get socialLike => AssetImage("assets/icons/icon-social-like.png"); + static AssetImage get socialLike => + AssetImage("assets/icons/icon-social-like.png"); - static AssetImage get socialRetweet => AssetImage("assets/icons/icon-social-retweet.png"); + static AssetImage get socialRetweet => + AssetImage("assets/icons/icon-social-retweet.png"); - static AssetImage get socialStar => AssetImage("assets/icons/icon-social-star.png"); + static AssetImage get socialStar => + AssetImage("assets/icons/icon-social-star.png"); - static AssetImage get starEmpty => AssetImage("assets/icons/icon-star-empty.png"); + static AssetImage get starEmpty => + AssetImage("assets/icons/icon-star-empty.png"); - static AssetImage get starFilled => AssetImage("assets/icons/icon-star-filled.png"); + static AssetImage get starFilled => + AssetImage("assets/icons/icon-star-filled.png"); static AssetImage get trash => AssetImage("assets/icons/icon-trash.png"); - static AssetImage get twitterActive => AssetImage("assets/icons/icon-twitter-active.png"); + static AssetImage get twitterActive => + AssetImage("assets/icons/icon-twitter-active.png"); - static AssetImage get twitterEmpty => AssetImage("assets/icons/icon-twitter-empty.png"); + static AssetImage get twitterEmpty => + AssetImage("assets/icons/icon-twitter-empty.png"); static AssetImage get user => AssetImage("assets/icons/icon-user.png"); diff --git a/flokk_src/lib/styled_components/styled_image_icon.dart b/flokk_src/lib/styled_components/styled_image_icon.dart index 22e73bf..438ebf1 100644 --- a/flokk_src/lib/styled_components/styled_image_icon.dart +++ b/flokk_src/lib/styled_components/styled_image_icon.dart @@ -12,7 +12,9 @@ class StyledImageIcon extends StatelessWidget { final Color color; final double size; - const StyledImageIcon(this.image, {Key? key, this.color = Colors.white, this.size = Sizes.iconMed}) : super(key: key); + const StyledImageIcon(this.image, + {Key? key, this.color = Colors.white, this.size = Sizes.iconMed}) + : super(key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/styled_components/styled_label_pill.dart b/flokk_src/lib/styled_components/styled_label_pill.dart index 759fc7c..33b551e 100644 --- a/flokk_src/lib/styled_components/styled_label_pill.dart +++ b/flokk_src/lib/styled_components/styled_label_pill.dart @@ -14,7 +14,12 @@ class StyledLabelPill extends StatelessWidget { final double borderRadius; final VoidCallback? onPressed; - const StyledLabelPill(this.text, {Key? key, this.textStyle, this.color, this.borderRadius = Corners.s5, this.onPressed}) + const StyledLabelPill(this.text, + {Key? key, + this.textStyle, + this.color, + this.borderRadius = Corners.s5, + this.onPressed}) : super(key: key); @override @@ -22,7 +27,8 @@ class StyledLabelPill extends StatelessWidget { AppTheme theme = context.watch(); String t = (text.length > 30) ? text.substring(0, 30) : text; return BaseStyledBtn( - contentPadding: EdgeInsets.symmetric(horizontal: Insets.m, vertical: Insets.sm), + contentPadding: + EdgeInsets.symmetric(horizontal: Insets.m, vertical: Insets.sm), onPressed: onPressed, bgColor: color ?? ColorUtils.blend(theme.surface, theme.bg2, .35), hoverColor: color ?? ColorUtils.blend(theme.surface, theme.bg2, .35), @@ -42,7 +48,8 @@ class ContactLabelPill extends StatelessWidget { final Color? color; final VoidCallback? onPressed; - const ContactLabelPill(this.text, {Key? key, this.color, this.onPressed}) : super(key: key); + const ContactLabelPill(this.text, {Key? key, this.color, this.onPressed}) + : super(key: key); @override Widget build(BuildContext context) { @@ -53,7 +60,8 @@ class ContactLabelPill extends StatelessWidget { onTap: onPressed, child: Container( alignment: Alignment.center, - padding: EdgeInsets.symmetric(horizontal: Insets.m, vertical: Insets.sm), + padding: + EdgeInsets.symmetric(horizontal: Insets.m, vertical: Insets.sm), decoration: BoxDecoration( color: color ?? theme.bg2.withOpacity(.35), borderRadius: Corners.s5Border, diff --git a/flokk_src/lib/styled_components/styled_progress_spinner.dart b/flokk_src/lib/styled_components/styled_progress_spinner.dart index 45b35ed..5895e2d 100644 --- a/flokk_src/lib/styled_components/styled_progress_spinner.dart +++ b/flokk_src/lib/styled_components/styled_progress_spinner.dart @@ -5,7 +5,8 @@ import 'package:provider/provider.dart'; class StyledProgressSpinner extends StatelessWidget { final Color color; - const StyledProgressSpinner({Key? key, this.color = Colors.white}) : super(key: key); + const StyledProgressSpinner({Key? key, this.color = Colors.white}) + : super(key: key); @override Widget build(BuildContext context) { @@ -15,7 +16,8 @@ class StyledProgressSpinner extends StatelessWidget { width: 24, height: 24, child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(theme.accent1Darker), backgroundColor: color), + valueColor: AlwaysStoppedAnimation(theme.accent1Darker), + backgroundColor: color), ), ); } diff --git a/flokk_src/lib/styled_components/styled_tab_bar.dart b/flokk_src/lib/styled_components/styled_tab_bar.dart index 4c0516e..2a5d1cf 100644 --- a/flokk_src/lib/styled_components/styled_tab_bar.dart +++ b/flokk_src/lib/styled_components/styled_tab_bar.dart @@ -11,14 +11,17 @@ class StyledTabBar extends StatelessWidget { final int index; static const List defaults = ["test", "foo", "bar"]; - const StyledTabBar({Key? key, this.sections = defaults, this.index = 0, this.onTabPressed}) : super(key: key); + const StyledTabBar( + {Key? key, this.sections = defaults, this.index = 0, this.onTabPressed}) + : super(key: key); @override Widget build(BuildContext context) { AppTheme theme = context.watch(); /// Create List of expanding sections's to fill the tab bar - List clickableLabels = sections.map((e) => _ClickableLabel(e, theme)).toList(); + List clickableLabels = + sections.map((e) => _ClickableLabel(e, theme)).toList(); /// Calculate target alignment for animated bar double targetAlignX = -1 + (index * 1 / (sections.length - 1)) * 2; @@ -47,7 +50,8 @@ class StyledTabBar extends StatelessWidget { decoration: BoxDecoration( color: fill, borderRadius: Corners.s5Border, - border: Border.all(color: border?.withOpacity(.35) ?? Colors.transparent)), + border: Border.all( + color: border?.withOpacity(.35) ?? Colors.transparent)), ); } @@ -58,10 +62,12 @@ class StyledTabBar extends StatelessWidget { return AnimatedDefaultTextStyle( duration: Durations.fast, - style: TextStyles.Footnote.textColor(isSelected ? selected : notSelected).scale(fontScale), + style: TextStyles.Footnote.textColor(isSelected ? selected : notSelected) + .scale(fontScale), child: OneLineText(e.toUpperCase()) .center() - .clickable(() => onTabPressed?.call(sections.indexOf(e)), opaque: true) + .clickable(() => onTabPressed?.call(sections.indexOf(e)), + opaque: true) .expanded(), ); } diff --git a/flokk_src/lib/styled_components/styled_text_input.dart b/flokk_src/lib/styled_components/styled_text_input.dart index 23904b0..887d1c6 100644 --- a/flokk_src/lib/styled_components/styled_text_input.dart +++ b/flokk_src/lib/styled_components/styled_text_input.dart @@ -8,7 +8,8 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; class StyledFormTextInput extends StatelessWidget { - static const EdgeInsets kDefaultTextInputPadding = EdgeInsets.only(bottom: Insets.sm, top: 4); + static const EdgeInsets kDefaultTextInputPadding = + EdgeInsets.only(bottom: Insets.sm, top: 4); final String label; final bool autoFocus; @@ -58,7 +59,8 @@ class StyledFormTextInput extends StatelessWidget { inputDecoration: InputDecoration( isDense: true, contentPadding: contentPadding, - border: ThinUnderlineBorder(borderSide: BorderSide(width: 5, color: Colors.red)), + border: ThinUnderlineBorder( + borderSide: BorderSide(width: 5, color: Colors.red)), //focusedBorder: UnderlineInputBorder(borderSide: BorderSide(width: .5, color: Colors.red)), hintText: hintText, ), @@ -139,7 +141,8 @@ class StyledSearchTextInputState extends State { @override void initState() { - _controller = widget.controller ?? TextEditingController(text: widget.initialValue); + _controller = + widget.controller ?? TextEditingController(text: widget.initialValue); _focusNode = FocusNode( debugLabel: widget.label, onKey: (FocusNode node, RawKeyEvent evt) { @@ -154,7 +157,8 @@ class StyledSearchTextInputState extends State { canRequestFocus: true, ); // Listen for focus out events - _focusNode.addListener(() => widget.onFocusChanged?.call(_focusNode.hasFocus)); + _focusNode + .addListener(() => widget.onFocusChanged?.call(_focusNode.hasFocus)); widget.onFocusCreated?.call(_focusNode); if (widget.autoFocus) { scheduleMicrotask(() => _focusNode.requestFocus()); @@ -252,7 +256,8 @@ class ThinUnderlineBorder extends InputBorder { bool get isOutline => false; @override - UnderlineInputBorder copyWith({BorderSide? borderSide, BorderRadius? borderRadius}) { + UnderlineInputBorder copyWith( + {BorderSide? borderSide, BorderRadius? borderRadius}) { return UnderlineInputBorder( borderSide: borderSide ?? this.borderSide, borderRadius: borderRadius ?? this.borderRadius, @@ -272,7 +277,8 @@ class ThinUnderlineBorder extends InputBorder { @override Path getInnerPath(Rect rect, {TextDirection? textDirection}) { return Path() - ..addRect(Rect.fromLTWH(rect.left, rect.top, rect.width, math.max(0.0, rect.height - borderSide.width))); + ..addRect(Rect.fromLTWH(rect.left, rect.top, rect.width, + math.max(0.0, rect.height - borderSide.width))); } @override @@ -318,7 +324,8 @@ class ThinUnderlineBorder extends InputBorder { TextDirection? textDirection, }) { print("Width: ${borderSide.width}"); - if (borderRadius.bottomLeft != Radius.zero || borderRadius.bottomRight != Radius.zero) + if (borderRadius.bottomLeft != Radius.zero || + borderRadius.bottomRight != Radius.zero) canvas.clipPath(getOuterPath(rect, textDirection: textDirection)); canvas.drawLine(rect.bottomLeft, rect.bottomRight, borderSide.toPaint()); } diff --git a/flokk_src/lib/styled_components/styled_user_avatar.dart b/flokk_src/lib/styled_components/styled_user_avatar.dart index 61f2ef3..ab013a1 100644 --- a/flokk_src/lib/styled_components/styled_user_avatar.dart +++ b/flokk_src/lib/styled_components/styled_user_avatar.dart @@ -7,7 +7,8 @@ class StyledUserAvatar extends StatefulWidget { final ContactData contact; final double size; - const StyledUserAvatar({Key? key, required this.contact, this.size = 50}) : super(key: key); + const StyledUserAvatar({Key? key, required this.contact, this.size = 50}) + : super(key: key); @override _StyledUserAvatarState createState() => _StyledUserAvatarState(); @@ -32,11 +33,11 @@ class _StyledUserAvatarState extends State { @override Widget build(BuildContext context) { - Widget child; if (widget.contact.profilePicBytes != null) { child = Image.memory(widget.contact.profilePicBytes!, fit: BoxFit.cover); - } else if (widget.contact.profilePic.isNotEmpty && !widget.contact.isDefaultPic) { + } else if (widget.contact.profilePic.isNotEmpty && + !widget.contact.isDefaultPic) { child = Image.network(widget.contact.profilePic, fit: BoxFit.cover); } else { child = AnimalAvatar(seed: _seed); @@ -92,7 +93,8 @@ class AnimalAvatar extends StatelessWidget { Container( color: backgrounds[r.nextInt(backgrounds.length)], ), - Image.asset("assets/images/birds/${foregrounds[r.nextInt(foregrounds.length)]}.png"), + Image.asset( + "assets/images/birds/${foregrounds[r.nextInt(foregrounds.length)]}.png"), ], ); } diff --git a/flokk_src/lib/styled_components/textinput_icon_row.dart b/flokk_src/lib/styled_components/textinput_icon_row.dart index fdb622e..1cc537d 100644 --- a/flokk_src/lib/styled_components/textinput_icon_row.dart +++ b/flokk_src/lib/styled_components/textinput_icon_row.dart @@ -14,7 +14,12 @@ class TextInputIconRow extends StatelessWidget { final void Function(bool)? onFocusChanged; const TextInputIconRow(this.icon, this.hintText, - {Key? key, this.autoFocus = false, this.initialValue = "", this.onChanged, this.onEditingComplete, this.onFocusChanged}) + {Key? key, + this.autoFocus = false, + this.initialValue = "", + this.onChanged, + this.onEditingComplete, + this.onFocusChanged}) : super(key: key); @override diff --git a/flokk_src/lib/styles.dart b/flokk_src/lib/styles.dart index 1b26ace..32f5f9c 100644 --- a/flokk_src/lib/styles.dart +++ b/flokk_src/lib/styles.dart @@ -115,13 +115,16 @@ class TextStyles { static TextStyle get Body3 => lato.size(FontSizes.s11); - static TextStyle get Callout => quicksand.size(FontSizes.s14).letterSpace(1.75); + static TextStyle get Callout => + quicksand.size(FontSizes.s14).letterSpace(1.75); static TextStyle get CalloutFocus => Callout.bold; - static TextStyle get Btn => quicksand.bold.size(FontSizes.s14).letterSpace(1.75); + static TextStyle get Btn => + quicksand.bold.size(FontSizes.s14).letterSpace(1.75); - static TextStyle get BtnSelected => quicksand.size(FontSizes.s14).letterSpace(1.75); + static TextStyle get BtnSelected => + quicksand.size(FontSizes.s14).letterSpace(1.75); static TextStyle get Footnote => quicksand.bold.size(FontSizes.s11); @@ -133,7 +136,7 @@ class Shadows { static double get mRadius => 8; - static List m(Color color, [ double opacity = 0]) { + static List m(Color color, [double opacity = 0]) { return enabled ? [ BoxShadow( @@ -149,7 +152,7 @@ class Shadows { offset: Offset(1, 0), ) ] - : const[]; + : const []; } } @@ -186,4 +189,3 @@ class Corners { static Radius get s10Radius => Radius.circular(s10); } - diff --git a/flokk_src/lib/tests/button_tests.dart b/flokk_src/lib/tests/button_tests.dart index a773017..8802d3f 100644 --- a/flokk_src/lib/tests/button_tests.dart +++ b/flokk_src/lib/tests/button_tests.dart @@ -27,7 +27,8 @@ class ButtonTests extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, separatorBuilder: () => VSpace(Insets.m), children: [ - ColorShiftIconBtn(StyledIcons.add, color: theme.accent1, onPressed: p), + ColorShiftIconBtn(StyledIcons.add, + color: theme.accent1, onPressed: p), ]), SeparatedColumn( mainAxisSize: MainAxisSize.min, @@ -38,7 +39,9 @@ class ButtonTests extends StatelessWidget { SecondaryBtn(child: FlutterLogo(), onPressed: p), SecondaryTextBtn("STAY ON THIS PAGE", onPressed: p), TransparentBtn( - child: Text("CLICK ME!", style: TextStyles.Footnote.textColor(theme.accent1)), onPressed: p), + child: Text("CLICK ME!", + style: TextStyles.Footnote.textColor(theme.accent1)), + onPressed: p), TransparentBtn( bigMode: true, child: Text( @@ -55,8 +58,13 @@ class ButtonTests extends StatelessWidget { children: [ PrimaryTextBtn("SAVE", onPressed: p), PrimaryTextBtn("SAVE", bigMode: true, onPressed: p), - PrimaryBtn(onPressed: p, child: Text("SAVE FOR WEB", style: TextStyles.Footnote)), - PrimaryBtn(onPressed: p, child: Text("SAVE FOR WEB", style: TextStyles.Footnote), bigMode: true), + PrimaryBtn( + onPressed: p, + child: Text("SAVE FOR WEB", style: TextStyles.Footnote)), + PrimaryBtn( + onPressed: p, + child: Text("SAVE FOR WEB", style: TextStyles.Footnote), + bigMode: true), ], ) ], diff --git a/flokk_src/lib/tests/command_testing_spike.dart b/flokk_src/lib/tests/command_testing_spike.dart index 24a6dc4..0dac2d7 100644 --- a/flokk_src/lib/tests/command_testing_spike.dart +++ b/flokk_src/lib/tests/command_testing_spike.dart @@ -28,7 +28,8 @@ class CommandTestingSpike extends StatelessWidget { RaisedButton( child: Text("refresh groups"), onPressed: () async { - List groups = await RefreshContactGroupsCommand(context).execute(); + List groups = + await RefreshContactGroupsCommand(context).execute(); print(groups.map((x) => x.name).toList().join(",")); }, ), @@ -49,15 +50,17 @@ class CommandTestingSpike extends StatelessWidget { child: Text("edit label"), onPressed: () async { group.name = "Renamed Label"; - group = (await RenameLabelCommand(context).execute(group)) ?? group; + group = + (await RenameLabelCommand(context).execute(group)) ?? group; print(group); }, ), RaisedButton( child: Text("add multiple labels to single contact"), onPressed: () async { - List userLabels = - contactModel.allGroups.where((x) => x.groupType == GroupType.UserContactGroup).toList(); + List userLabels = contactModel.allGroups + .where((x) => x.groupType == GroupType.UserContactGroup) + .toList(); int length = min(userLabels.length, 3); List firstThreeLabels = userLabels.sublist(0, length); contact.groupList = firstThreeLabels; @@ -71,21 +74,27 @@ class CommandTestingSpike extends StatelessWidget { child: Text("add single label to multiple contacts"), onPressed: () async { if (contactModel.allGroups.isNotEmpty) { - GroupData firstLabel = - contactModel.allGroups.where((x) => x.groupType == GroupType.UserContactGroup).first; - List faves = contactModel.allContacts.where((x) => x.isStarred == true).toList(); + GroupData firstLabel = contactModel.allGroups + .where((x) => x.groupType == GroupType.UserContactGroup) + .first; + List faves = contactModel.allContacts + .where((x) => x.isStarred == true) + .toList(); int length = min(faves.length, 3); List firstThreeContacts = faves.sublist(0, length); - AddLabelToContactCommand(context).execute(firstThreeContacts, existingGroup: firstLabel); - print("Add ${firstLabel.name} to ${firstThreeContacts.map((x) => x.nameFull).toList().join(', ')}"); + AddLabelToContactCommand(context) + .execute(firstThreeContacts, existingGroup: firstLabel); + print( + "Add ${firstLabel.name} to ${firstThreeContacts.map((x) => x.nameFull).toList().join(', ')}"); } }, ), RaisedButton( child: Text("add new label to contact"), onPressed: () async { - List updatedContact = await AddLabelToContactCommand(context) - .execute([contact], existingGroup: GroupData(), newLabel: "Foo"); + List updatedContact = + await AddLabelToContactCommand(context).execute([contact], + existingGroup: GroupData(), newLabel: "Foo"); print(updatedContact.first); }, ), @@ -93,14 +102,17 @@ class CommandTestingSpike extends StatelessWidget { child: Text("add existing label to contact"), onPressed: () async { List updatedContact = - await AddLabelToContactCommand(context).execute([contact], existingGroup: group); + await AddLabelToContactCommand(context) + .execute([contact], existingGroup: group); print(updatedContact.first); }, ), RaisedButton( child: Text("remove label from contact"), onPressed: () async { - ContactData updatedContact = await RemoveLabelFromContactCommand(context).execute(contact, group); + ContactData updatedContact = + await RemoveLabelFromContactCommand(context) + .execute(contact, group); print(updatedContact); }, ), diff --git a/flokk_src/lib/themes.dart b/flokk_src/lib/themes.dart index 48a5bc5..26a6343 100644 --- a/flokk_src/lib/themes.dart +++ b/flokk_src/lib/themes.dart @@ -142,5 +142,6 @@ class AppTheme { toggleableActiveColor: accent1); } - Color shift(Color c, double d) => ColorUtils.shiftHsl(c, d * (isDark? -1 : 1)); + Color shift(Color c, double d) => + ColorUtils.shiftHsl(c, d * (isDark ? -1 : 1)); } diff --git a/flokk_src/lib/views/contact_edit/contact_edit_panel.dart b/flokk_src/lib/views/contact_edit/contact_edit_panel.dart index 56167f5..e0b686f 100644 --- a/flokk_src/lib/views/contact_edit/contact_edit_panel.dart +++ b/flokk_src/lib/views/contact_edit/contact_edit_panel.dart @@ -35,7 +35,11 @@ class ContactEditForm extends StatefulWidget { final String initialSection; const ContactEditForm( - {Key? key, required this.contact, required this.contactsModel, this.onEditComplete, this.initialSection = ""}) + {Key? key, + required this.contact, + required this.contactsModel, + this.onEditComplete, + this.initialSection = ""}) : super(key: key); @override @@ -99,14 +103,16 @@ class ContactEditFormState extends State { //Continue to add new contact else { // Wait for add-new command to complete, since it would be overly complicated to create a tmpUser - contact = await UpdateContactCommand(context).execute(contact, updateSocial: contact.hasAnySocial); + contact = await UpdateContactCommand(context) + .execute(contact, updateSocial: contact.hasAnySocial); // If we have a valid contact here, all is good success = contact != ContactData(); } } else { bool hasSocialChanged = contact.hasSameSocial(widget.contact) == false; - await UpdateContactCommand(context).execute(contact, updateSocial: hasSocialChanged); + await UpdateContactCommand(context) + .execute(contact, updateSocial: hasSocialChanged); } if (success) { widget.onEditComplete?.call(contact); @@ -118,7 +124,8 @@ class ContactEditFormState extends State { } } - void handleDeletePressed() async => await DeleteContactCommand(context).execute([widget.contact]); + void handleDeletePressed() async => + await DeleteContactCommand(context).execute([widget.contact]); void handleCancelPressed() async { bool doCancel = true; @@ -127,7 +134,8 @@ class ContactEditFormState extends State { } if (doCancel) { /// If we're cancelling a new contact, return null indicating that it should be discarded - widget.onEditComplete?.call(tmpContact.isNew ? ContactData() : widget.contact); + widget.onEditComplete + ?.call(tmpContact.isNew ? ContactData() : widget.contact); } } diff --git a/flokk_src/lib/views/contact_edit/contact_edit_panel_view.dart b/flokk_src/lib/views/contact_edit/contact_edit_panel_view.dart index a77ece5..b0e4ee6 100644 --- a/flokk_src/lib/views/contact_edit/contact_edit_panel_view.dart +++ b/flokk_src/lib/views/contact_edit/contact_edit_panel_view.dart @@ -28,8 +28,10 @@ import 'package:flokk/views/contact_edit/miniforms/website_miniform.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class ContactEditFormView extends WidgetView { - ContactEditFormView(ContactEditFormState state, {Key? key}) : super(state, key: key); +class ContactEditFormView + extends WidgetView { + ContactEditFormView(ContactEditFormState state, {Key? key}) + : super(state, key: key); BuildContext get context => state.context; @@ -101,7 +103,8 @@ class ContactEditFormView extends WidgetView extends StatefulWidget { super(key: key); @override - _ExpandingMiniformContainerState createState() => _ExpandingMiniformContainerState(); + _ExpandingMiniformContainerState createState() => + _ExpandingMiniformContainerState(); } -class _ExpandingMiniformContainerState extends State with TickerProviderStateMixin { +class _ExpandingMiniformContainerState extends State + with TickerProviderStateMixin { bool? _isOpen; String _hint = ""; Timer? timer; @@ -112,7 +114,8 @@ class _ExpandingMiniformContainerState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ /// Left Icon - StyledImageIcon(widget.icon, size: 20, color: theme.grey).translate(offset: Offset(0, 8)), + StyledImageIcon(widget.icon, size: 20, color: theme.grey) + .translate(offset: Offset(0, 8)), HSpace(Insets.l), /// Content - Either the miniform, or the StyledText @@ -120,7 +123,9 @@ class _ExpandingMiniformContainerState extends State // Mini-Form ? widget.formBuilder() // Empty Prompt Text - : StyledFormTextInput(hintText: _hint, onFocusChanged: _handlePromptFocusChanged) + : StyledFormTextInput( + hintText: _hint, + onFocusChanged: _handlePromptFocusChanged) .padding(right: Insets.l * 1.5 - 2)) .padding(right: Insets.m) .flexible(), diff --git a/flokk_src/lib/views/contact_edit/miniforms/address_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/address_miniform.dart index 8c795c4..fe18813 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/address_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/address_miniform.dart @@ -9,7 +9,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactAddressMiniForm extends BaseMiniForm { - ContactAddressMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.address, key: key); + ContactAddressMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.address, key: key); @override Widget build(BuildContext context) { @@ -23,45 +24,51 @@ class ContactAddressMiniForm extends BaseMiniForm { builder: (context) { if (c.addressList.isEmpty) c.addressList.add(AddressData()); List kids = c.addressList.map((a) { - return SeparatedColumn(key: ObjectKey(a), separatorBuilder: () => VSpace(Insets.xs), children: [ - /// Street + Type - buildTextWithDropdown( - context, - null, - autoFocus: getIsFocused(c.addressList, a), - hint: "Street", - typeHint: "Type", - initialText: a.singleLineStreet, - initialType: a.type, - types: types.map((e) => e.toUpperCase()).toList(), - onTextChanged: (value) => setFormState(() => a.street = value), - onTypeChanged: (value) => setFormState(() => a.type = value), - onDelete: () => handleDeletePressed(context, a, c.addressList), - showDelete: !a.isEmpty, - typeWidth: 160, - ), + return SeparatedColumn( + key: ObjectKey(a), + separatorBuilder: () => VSpace(Insets.xs), + children: [ + /// Street + Type + buildTextWithDropdown( + context, + null, + autoFocus: getIsFocused(c.addressList, a), + hint: "Street", + typeHint: "Type", + initialText: a.singleLineStreet, + initialType: a.type, + types: types.map((e) => e.toUpperCase()).toList(), + onTextChanged: (value) => + setFormState(() => a.street = value), + onTypeChanged: (value) => + setFormState(() => a.type = value), + onDelete: () => handleDeletePressed( + context, a, c.addressList), + showDelete: !a.isEmpty, + typeWidth: 160, + ), - /// City / State - buildDualTextInput( - context, - "City", - a.city, - (v) => setFormState(() => a.city = v), - "State", - a.region, - (v) => setFormState(() => a.region = v), - ).padding(right: rightPadding), + /// City / State + buildDualTextInput( + context, + "City", + a.city, + (v) => setFormState(() => a.city = v), + "State", + a.region, + (v) => setFormState(() => a.region = v), + ).padding(right: rightPadding), - /// Country / Postal Code - buildDualTextInput( - context, - "Postal Code", - a.postcode, - (v) => setFormState(() => a.postcode = v), - "Country", - a.country, - (v) => setFormState(() => a.country = v), - ).padding(right: rightPadding), + /// Country / Postal Code + buildDualTextInput( + context, + "Postal Code", + a.postcode, + (v) => setFormState(() => a.postcode = v), + "Country", + a.country, + (v) => setFormState(() => a.country = v), + ).padding(right: rightPadding), //TODO: Put the country-dropdown back in when we have time to debug the height issue. // buildTextWithDropdown( // context, @@ -77,13 +84,14 @@ class ContactAddressMiniForm extends BaseMiniForm { // typeWidth: 160, // ), - if (c.addressList.indexOf(a) < c.addressList.length - 1) VSpace(Insets.m), - ]); + if (c.addressList.indexOf(a) < c.addressList.length - 1) + VSpace(Insets.m), + ]); }).toList(); /// Maybe add addNew btn - injectAddNewBtnIfNecessary( - "Add $sectionType", kids, c.addressList, (a) => a.isEmpty, () => AddressData()); + injectAddNewBtnIfNecessary("Add $sectionType", kids, + c.addressList, (a) => a.isEmpty, () => AddressData()); return SeparatedColumn( separatorBuilder: () => VSpace(Insets.sm), crossAxisAlignment: CrossAxisAlignment.start, diff --git a/flokk_src/lib/views/contact_edit/miniforms/base_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/base_miniform.dart index 9476690..6c25c8d 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/base_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/base_miniform.dart @@ -32,7 +32,8 @@ abstract class BaseMiniForm extends StatelessWidget { ContactData get c => form.tmpContact; - bool getIsFocused(List list, T item) => isSelected && list.indexOf(item) == 0; + bool getIsFocused(List list, T item) => + isSelected && list.indexOf(item) == 0; /// ///////////////////////////////////////////////////// /// SHARED HANDLERS AND BUSINESS LOGIC @@ -41,7 +42,8 @@ abstract class BaseMiniForm extends StatelessWidget { form.rebuild(); } - void handleFocusChanged(bool value, BuildContext context) => FocusChangedNotification(value).dispatch(context); + void handleFocusChanged(bool value, BuildContext context) => + FocusChangedNotification(value).dispatch(context); void handleDeletePressed(BuildContext context, T item, List list) { // Remove item @@ -61,8 +63,8 @@ abstract class BaseMiniForm extends StatelessWidget { /// SHARED UI FACTORY BUILD METHODS /// Adds a build button if the final row in the list has some content, and we don't exceed some max # of items - void injectAddNewBtnIfNecessary( - String hint, List column, List list, Function(T) isEmpty, Function() itemBuilder) { + void injectAddNewBtnIfNecessary(String hint, List column, + List list, Function(T) isEmpty, Function() itemBuilder) { int maxItems = 8; if (list.isNotEmpty && !isEmpty(list.last) && list.length < maxItems) { Widget btn = TransparentIconAndTextBtn( @@ -80,7 +82,8 @@ abstract class BaseMiniForm extends StatelessWidget { /// ////////////////////////////////////////////////////////////// /// Creates an ExpandingMiniformContainer with some shared boilerplate (auto-focus check, and onOpened handler). /// Every miniform calls this fxn. - Widget buildExpandingContainer(dynamic icon, {required BoolCallback hasContent, required FormBuilder formBuilder}) { + Widget buildExpandingContainer(dynamic icon, + {required BoolCallback hasContent, required FormBuilder formBuilder}) { return ExpandingMiniformContainer( sectionType, icon, @@ -96,7 +99,8 @@ abstract class BaseMiniForm extends StatelessWidget { /// ////////////////////////////////////////////////// /// Builds a basic TextInput that dispatches focusChanged /// //TODO SB: Move this and the other components into their own widgets. They just need to be passed the miniform as a component. - Widget buildTextInput(BuildContext context, String hint, String? initial, void Function(String)? onChanged, + Widget buildTextInput(BuildContext context, String hint, String? initial, + void Function(String)? onChanged, {bool autoFocus = false, EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding, int? maxLines = 1, @@ -115,15 +119,26 @@ abstract class BaseMiniForm extends StatelessWidget { /// ////////////////////////////////////////////////// /// Builds a dual-column TextInput like those used in Address - Widget buildDualTextInput(BuildContext context, String hint1, String initial1, Function(String) onChanged1, - String hint2, String initial2, Function(String) onChanged2, - {bool autoFocus = false, EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding, int maxLines = 1}) { + Widget buildDualTextInput( + BuildContext context, + String hint1, + String initial1, + Function(String) onChanged1, + String hint2, + String initial2, + Function(String) onChanged2, + {bool autoFocus = false, + EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding, + int maxLines = 1}) { return Row( children: [ - buildTextInput(context, hint1, initial1, onChanged1, autoFocus: autoFocus, padding: padding, maxLines: maxLines) + buildTextInput(context, hint1, initial1, onChanged1, + autoFocus: autoFocus, padding: padding, maxLines: maxLines) .flexible(), HSpace(Insets.m), - buildTextInput(context, hint2, initial2, onChanged2, padding: padding, maxLines: maxLines).flexible(), + buildTextInput(context, hint2, initial2, onChanged2, + padding: padding, maxLines: maxLines) + .flexible(), ], ); } @@ -136,7 +151,7 @@ abstract class BaseMiniForm extends StatelessWidget { String typeHint = "", String? initialText, String? initialType, - List types = const[], + List types = const [], void Function(String)? onTextChanged, void Function(String)? onTypeChanged, VoidCallback? onDelete, @@ -159,12 +174,14 @@ abstract class BaseMiniForm extends StatelessWidget { /// Type dropdown StyledAutoCompleteDropdown( - items: types, - hint: typeHint, - initialValue: initialType, - onChanged: onTypeChanged, - maxHeight: maxDropdownHeight, - onFocusChanged: (v) => handleFocusChanged(v, context)).width(typeWidth).translate(offset: Offset(0, 3)), + items: types, + hint: typeHint, + initialValue: initialType, + onChanged: onTypeChanged, + maxHeight: maxDropdownHeight, + onFocusChanged: (v) => handleFocusChanged(v, context)) + .width(typeWidth) + .translate(offset: Offset(0, 3)), HSpace(2), /// Delete Btn @@ -173,7 +190,9 @@ abstract class BaseMiniForm extends StatelessWidget { size: 20, onPressed: showDelete ? onDelete : null, padding: EdgeInsets.all(Insets.sm), - ).opacity(showDelete ? 1 : 0, animate: true).animate(Durations.fast, Curves.linear), + ) + .opacity(showDelete ? 1 : 0, animate: true) + .animate(Durations.fast, Curves.linear), ], ); } @@ -184,7 +203,8 @@ abstract class BaseMiniForm extends StatelessWidget { BuildContext context, String hint, String typeHint, { - List itemList = const [], // NOTE CE: Dart really fails here, default argument values must be const but generic type arguments cannot be used in a const context + List itemList = + const [], // NOTE CE: Dart really fails here, default argument values must be const but generic type arguments cannot be used in a const context List types = const [], required T Function() newItemBuilder, required bool Function(T) isEmpty, @@ -215,7 +235,8 @@ abstract class BaseMiniForm extends StatelessWidget { }).toList(); /// Add a "Add New" btn to the column if certain conditions are met - injectAddNewBtnIfNecessary(hint, kids, itemList, isEmpty, newItemBuilder); + injectAddNewBtnIfNecessary( + hint, kids, itemList, isEmpty, newItemBuilder); /// Return the actual Column of content return SeparatedColumn( diff --git a/flokk_src/lib/views/contact_edit/miniforms/birthday_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/birthday_miniform.dart index ab57bf2..b3a5c31 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/birthday_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/birthday_miniform.dart @@ -5,7 +5,8 @@ import 'package:flokk/views/contact_edit/miniforms/controls/textfield_with_date_ import 'package:flutter/material.dart'; class ContactBirthdayMiniForm extends BaseMiniForm { - ContactBirthdayMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.birthday, key: key); + ContactBirthdayMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.birthday, key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/views/contact_edit/miniforms/controls/textfield_with_date_picker_row.dart b/flokk_src/lib/views/contact_edit/miniforms/controls/textfield_with_date_picker_row.dart index 0d16f6d..d4063ce 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/controls/textfield_with_date_picker_row.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/controls/textfield_with_date_picker_row.dart @@ -10,7 +10,6 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; - class TextfieldWithDatePickerRow extends StatefulWidget { final BaseMiniForm miniform; final bool isSelected; @@ -28,11 +27,12 @@ class TextfieldWithDatePickerRow extends StatefulWidget { }) : super(key: key); @override - _TextfieldWithDatePickerRowState createState() => _TextfieldWithDatePickerRowState(); + _TextfieldWithDatePickerRowState createState() => + _TextfieldWithDatePickerRowState(); } -class _TextfieldWithDatePickerRowState extends State { - +class _TextfieldWithDatePickerRowState + extends State { late TextEditingController textController; void handleDatePicked(BuildContext context) async { @@ -72,7 +72,8 @@ class _TextfieldWithDatePickerRowState extends State super.initState(); } - _handleFocusChanged(bool value) => FocusChangedNotification(value).dispatch(context); + _handleFocusChanged(bool value) => + FocusChangedNotification(value).dispatch(context); @override Widget build(BuildContext context) { @@ -100,5 +101,4 @@ class _TextfieldWithDatePickerRowState extends State ], ); } - } diff --git a/flokk_src/lib/views/contact_edit/miniforms/email_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/email_miniform.dart index f721612..06ff6a2 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/email_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/email_miniform.dart @@ -5,7 +5,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactEmailMiniForm extends BaseMiniForm { - ContactEmailMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.email, key: key); + ContactEmailMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.email, key: key); @override Widget build(BuildContext context) { @@ -15,7 +16,8 @@ class ContactEmailMiniForm extends BaseMiniForm { formBuilder: () { // Wrap content in a builder so the FocusNotification will get caught by the ExpandingFormContainer return Builder( - builder: (context) => buildColumnOfTextWithDropdown(context, "Email Address", "Type", + builder: (context) => buildColumnOfTextWithDropdown( + context, "Email Address", "Type", itemList: c.emailList, types: ["Home", "Work", "Other"], newItemBuilder: () => EmailData(), diff --git a/flokk_src/lib/views/contact_edit/miniforms/events_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/events_miniform.dart index 5f0e69a..083648b 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/events_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/events_miniform.dart @@ -13,7 +13,8 @@ import 'package:flokk/views/contact_edit/miniforms/controls/textfield_with_date_ import 'package:flutter/material.dart'; class ContactEventsMiniForm extends BaseMiniForm { - ContactEventsMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.events, key: key); + ContactEventsMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.events, key: key); @override Widget build(BuildContext context) { @@ -35,7 +36,9 @@ class ContactEventsMiniForm extends BaseMiniForm { typeHint: "Type", initialText: DateFormats.google.format(item.date), initialType: item.type, - types: ["Anniversary", "Hire Date", "Other"].map((e) => e.toUpperCase()).toList(), + types: ["Anniversary", "Hire Date", "Other"] + .map((e) => e.toUpperCase()) + .toList(), onDateChanged: (s, d) => setFormState(() => item.date = d), onTypeChanged: (value) => setFormState(() => item.type = value), onDelete: () => handleDeletePressed(context, item, itemList), @@ -43,11 +46,12 @@ class ContactEventsMiniForm extends BaseMiniForm { }).toList(); /// Add a "Add New" btn to the column if certain conditions are met - injectAddNewBtnIfNecessary("Event", kids, itemList, (e) => e.isEmpty, newItemBuilder); + injectAddNewBtnIfNecessary( + "Event", kids, itemList, (e) => e.isEmpty, newItemBuilder); /// Return the actual Column of content return SeparatedColumn( - separatorBuilder: ()=>VSpace(Insets.sm * 1.5), + separatorBuilder: () => VSpace(Insets.sm * 1.5), crossAxisAlignment: CrossAxisAlignment.start, children: kids, ); @@ -82,11 +86,13 @@ class ContactEventsMiniForm extends BaseMiniForm { /// Type dropdown StyledAutoCompleteDropdown( - items: types, - hint: typeHint, - initialValue: initialType, - onChanged: onTypeChanged, - onFocusChanged: (v) => handleFocusChanged(v, context)).width(typeWidth).translate(offset: Offset(0, 3)), + items: types, + hint: typeHint, + initialValue: initialType, + onChanged: onTypeChanged, + onFocusChanged: (v) => handleFocusChanged(v, context)) + .width(typeWidth) + .translate(offset: Offset(0, 3)), HSpace(2), /// Delete Btn @@ -95,7 +101,9 @@ class ContactEventsMiniForm extends BaseMiniForm { size: 20, onPressed: showDelete ? onDelete : null, padding: EdgeInsets.all(Insets.sm), - ).opacity(showDelete ? 1 : 0, animate: true).animate(Durations.fast, Curves.linear), + ) + .opacity(showDelete ? 1 : 0, animate: true) + .animate(Durations.fast, Curves.linear), ], ); } diff --git a/flokk_src/lib/views/contact_edit/miniforms/job_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/job_miniform.dart index 3fa364d..3220d44 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/job_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/job_miniform.dart @@ -6,7 +6,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactJobMiniForm extends BaseMiniForm { - ContactJobMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.job, key: key); + ContactJobMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.job, key: key); @override Widget build(BuildContext context) { @@ -18,8 +19,11 @@ class ContactJobMiniForm extends BaseMiniForm { return Builder( builder: (context) => SeparatedColumn( children: [ - buildTextInput(context, "Company", c.jobCompany, (v) => c.jobCompany = v, autoFocus: isSelected), - buildTextInput(context, "Job Title", c.jobTitle, (v) => c.jobTitle = v), + buildTextInput( + context, "Company", c.jobCompany, (v) => c.jobCompany = v, + autoFocus: isSelected), + buildTextInput( + context, "Job Title", c.jobTitle, (v) => c.jobTitle = v), ], ).padding(right: rightPadding), ); diff --git a/flokk_src/lib/views/contact_edit/miniforms/label_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/label_miniform.dart index f14d293..97e5c21 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/label_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/label_miniform.dart @@ -14,7 +14,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class ContactLabelMiniForm extends BaseMiniForm { - ContactLabelMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.label, key: key); + ContactLabelMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.label, key: key); void _handleAddLabel(String label, BuildContext context) { // If the label is empty or we already have that label on our contact then dont add it @@ -25,7 +26,9 @@ class ContactLabelMiniForm extends BaseMiniForm { setFormState(() => c.groupList.add(groupToAdd)); } else { // We must make a new group, add that group to this contact when the creation has finished - CreateLabelCommand(context).execute(label).then((g) => setFormState(() => c.groupList.add(g))); + CreateLabelCommand(context) + .execute(label) + .then((g) => setFormState(() => c.groupList.add(g))); } } @@ -47,7 +50,9 @@ class ContactLabelMiniForm extends BaseMiniForm { onAddLabel: (label) => _handleAddLabel(label, context), onRemoveLabel: _handleRemoveLabel, contactLabels: c.groupList.map((g) => g.name).toList(), - allLabels: form.widget.contactsModel.allGroups.map((g) => g.name).toList(), + allLabels: form.widget.contactsModel.allGroups + .map((g) => g.name) + .toList(), onFocusChanged: (v) => handleFocusChanged(v, context), ).padding(right: rightPadding); }, @@ -75,7 +80,8 @@ class _LabelMiniformWithSearch extends StatefulWidget { }); @override - _LabelMiniformWithSearchState createState() => _LabelMiniformWithSearchState(); + _LabelMiniformWithSearchState createState() => + _LabelMiniformWithSearchState(); } class _LabelMiniformWithSearchState extends State<_LabelMiniformWithSearch> { @@ -143,7 +149,9 @@ class _LabelMiniformWithSearchState extends State<_LabelMiniformWithSearch> { onFocusChanged: _handleTextFocusChanged, ), if (_isOpen!) ...{ - Text("Suggestions".toUpperCase(), style: TextStyles.Caption.textColor(theme.grey)).padding(bottom: Insets.m), + Text("Suggestions".toUpperCase(), + style: TextStyles.Caption.textColor(theme.grey)) + .padding(bottom: Insets.m), Wrap( runSpacing: Insets.sm * 1.5, spacing: Insets.sm, diff --git a/flokk_src/lib/views/contact_edit/miniforms/name_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/name_miniform.dart index f2718a4..51c29ce 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/name_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/name_miniform.dart @@ -8,7 +8,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactNameMiniForm extends BaseMiniForm { - ContactNameMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.name, key: key); + ContactNameMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.name, key: key); @override Widget build(BuildContext context) { @@ -19,12 +20,22 @@ class ContactNameMiniForm extends BaseMiniForm { /// Wrap content in a builder so the FocusNotification will get caught by the ExpandingFormContainer return Builder( builder: (context) => SeparatedColumn( - separatorBuilder: ()=>VSpace(Insets.sm * .5), + separatorBuilder: () => VSpace(Insets.sm * .5), children: [ - buildTextInput(context, "First Name", c.nameGiven, (v) => c.nameGiven = v, autoFocus: isSelected), - buildTextInput(context, "Middle Name", c.nameMiddle, (v) => c.nameMiddle = v), - buildTextInput(context, "Last Name", c.nameFamily, (v) => c.nameFamily = v), - buildDualTextInput(context, "Prefix", c.namePrefix, (v) => c.namePrefix = v, "Suffix", c.nameSuffix, + buildTextInput( + context, "First Name", c.nameGiven, (v) => c.nameGiven = v, + autoFocus: isSelected), + buildTextInput(context, "Middle Name", c.nameMiddle, + (v) => c.nameMiddle = v), + buildTextInput( + context, "Last Name", c.nameFamily, (v) => c.nameFamily = v), + buildDualTextInput( + context, + "Prefix", + c.namePrefix, + (v) => c.namePrefix = v, + "Suffix", + c.nameSuffix, (v) => c.nameSuffix = v), ], ).padding(right: rightPadding), diff --git a/flokk_src/lib/views/contact_edit/miniforms/notes_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/notes_miniform.dart index 34033d5..de97fdc 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/notes_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/notes_miniform.dart @@ -6,7 +6,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactNotesMiniForm extends BaseMiniForm { - ContactNotesMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.notes, key: key); + ContactNotesMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.notes, key: key); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/views/contact_edit/miniforms/phone_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/phone_miniform.dart index ba28e26..8a8ac4d 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/phone_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/phone_miniform.dart @@ -5,7 +5,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactPhoneMiniForm extends BaseMiniForm { - ContactPhoneMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.phone, key: key); + ContactPhoneMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.phone, key: key); @override Widget build(BuildContext context) { @@ -15,9 +16,19 @@ class ContactPhoneMiniForm extends BaseMiniForm { formBuilder: () { /// Wrap content in a builder so the FocusNotification will get caught by the ExpandingFormContainer return Builder( - builder: (context) => buildColumnOfTextWithDropdown(context, "Phone Number", "Type", + builder: (context) => buildColumnOfTextWithDropdown( + context, "Phone Number", "Type", itemList: c.phoneList, - types: ["Work", "Other", "Mobile", "Main", "Home Fax", "Work Fax", "Google Voice", "Pager"], + types: [ + "Work", + "Other", + "Mobile", + "Main", + "Home Fax", + "Work Fax", + "Google Voice", + "Pager" + ], newItemBuilder: () => PhoneData(), isEmpty: (PhoneData i) => i.isEmpty, getValue: (i) => i.number, diff --git a/flokk_src/lib/views/contact_edit/miniforms/relationship_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/relationship_miniform.dart index e21a537..35f2511 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/relationship_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/relationship_miniform.dart @@ -7,7 +7,8 @@ import 'package:flutter/material.dart'; class ContactRelationshipMiniForm extends BaseMiniForm { final double maxDropdownHeight; - ContactRelationshipMiniForm(ContactEditFormState form, {Key? key, required this.maxDropdownHeight}) + ContactRelationshipMiniForm(ContactEditFormState form, + {Key? key, required this.maxDropdownHeight}) : super(form, ContactSectionType.relationship, key: key); @override diff --git a/flokk_src/lib/views/contact_edit/miniforms/social_miniforms.dart b/flokk_src/lib/views/contact_edit/miniforms/social_miniforms.dart index 110504e..558f9f7 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/social_miniforms.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/social_miniforms.dart @@ -12,7 +12,12 @@ class ContactSocialMiniForm extends BaseMiniForm { final SocialActivityType type; ContactSocialMiniForm(ContactEditFormState form, this.type, {Key? key}) - : super(form, type == SocialActivityType.Git ? ContactSectionType.github : ContactSectionType.twitter, key: key); + : super( + form, + type == SocialActivityType.Git + ? ContactSectionType.github + : ContactSectionType.twitter, + key: key); bool get isGit => type == SocialActivityType.Git; @@ -25,9 +30,11 @@ class ContactSocialMiniForm extends BaseMiniForm { // Wrap content in a builder so the FocusNotification will get caught by the ExpandingFormContainer return Builder(builder: (context) { if (type == SocialActivityType.Git) { - return buildPrefixedTextInput(context, "github.com/", c.gitUsername, (v) => c.gitUsername = v); + return buildPrefixedTextInput(context, "github.com/", c.gitUsername, + (v) => c.gitUsername = v); } else { - return buildPrefixedTextInput(context, "@", c.twitterHandle, (v) => c.twitterHandle = v); + return buildPrefixedTextInput( + context, "@", c.twitterHandle, (v) => c.twitterHandle = v); } }).padding(right: rightPadding); }, @@ -35,10 +42,12 @@ class ContactSocialMiniForm extends BaseMiniForm { } /// Builds prefixed TextInput used for git/twitter - Widget buildPrefixedTextInput(BuildContext context, String hint, String initial, Function(String) onChanged, + Widget buildPrefixedTextInput(BuildContext context, String hint, + String initial, Function(String) onChanged, [bool autoFocus = false]) { double prefixSize = StringUtils.measure(hint, TextStyles.Body1).width; - EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding.copyWith(left: prefixSize + .5); + EdgeInsets padding = StyledFormTextInput.kDefaultTextInputPadding + .copyWith(left: prefixSize + .5); return FocusTraversalGroup( child: Stack( children: [ @@ -50,7 +59,8 @@ class ContactSocialMiniForm extends BaseMiniForm { ), /// Value text - buildTextInput(context, "", initial, onChanged, autoFocus: isSelected, padding: padding), + buildTextInput(context, "", initial, onChanged, + autoFocus: isSelected, padding: padding), ], ), ); diff --git a/flokk_src/lib/views/contact_edit/miniforms/website_miniform.dart b/flokk_src/lib/views/contact_edit/miniforms/website_miniform.dart index 1cc7e45..4840d5c 100644 --- a/flokk_src/lib/views/contact_edit/miniforms/website_miniform.dart +++ b/flokk_src/lib/views/contact_edit/miniforms/website_miniform.dart @@ -5,7 +5,8 @@ import 'package:flokk/views/contact_edit/miniforms/base_miniform.dart'; import 'package:flutter/material.dart'; class ContactWebsiteMiniForm extends BaseMiniForm { - ContactWebsiteMiniForm(ContactEditFormState form, {Key? key}) : super(form, ContactSectionType.websites, key: key); + ContactWebsiteMiniForm(ContactEditFormState form, {Key? key}) + : super(form, ContactSectionType.websites, key: key); @override Widget build(BuildContext context) { @@ -15,7 +16,8 @@ class ContactWebsiteMiniForm extends BaseMiniForm { formBuilder: () { // Wrap content in a builder so the FocusNotification will get caught by the ExpandingFormContainer return Builder( - builder: (context) => buildColumnOfTextWithDropdown(context, "Link", "Type", + builder: (context) => buildColumnOfTextWithDropdown( + context, "Link", "Type", itemList: c.websiteList, types: ["Blog", "Home Page", "Profile", "Work"], newItemBuilder: () => WebsiteData(), diff --git a/flokk_src/lib/views/contact_info/contact_info_details_card.dart b/flokk_src/lib/views/contact_info/contact_info_details_card.dart index 957575c..f7937f5 100644 --- a/flokk_src/lib/views/contact_info/contact_info_details_card.dart +++ b/flokk_src/lib/views/contact_info/contact_info_details_card.dart @@ -17,11 +17,13 @@ class ContactInfoDetailsCard extends StatelessWidget { void _handleEmailPressed(String value) => UrlLauncher.openEmail(value); - void _handleLocationPressed(String value) => UrlLauncher.openGoogleMaps(value); + void _handleLocationPressed(String value) => + UrlLauncher.openGoogleMaps(value); void _handleGitPressed(String value) => UrlLauncher.openGitUser(value); - void _handleTwitterPressed(String value) => UrlLauncher.openTwitterUser(value); + void _handleTwitterPressed(String value) => + UrlLauncher.openTwitterUser(value); void _handleLinkPressed(String value) => UrlLauncher.openHttp(value); @@ -39,7 +41,8 @@ class ContactInfoDetailsCard extends StatelessWidget { icon: StyledIcons.mail, onPressed: _handleEmailPressed, editType: ContactSectionType.email, - rows: contact.emailList.map((e) => Tuple2(e.value, e.type)).toList(), + rows: + contact.emailList.map((e) => Tuple2(e.value, e.type)).toList(), ), /// PHONE @@ -48,7 +51,8 @@ class ContactInfoDetailsCard extends StatelessWidget { icon: StyledIcons.phone, onPressed: _handlePhonePressed, editType: ContactSectionType.phone, - rows: contact.phoneList.map((e) => Tuple2(e.number, e.type)).toList(), + rows: + contact.phoneList.map((e) => Tuple2(e.number, e.type)).toList(), ), /// SOCIAL @@ -72,43 +76,59 @@ class ContactInfoDetailsCard extends StatelessWidget { MultilineClickableIconRow( icon: StyledIcons.address, onPressed: _handleLocationPressed, - rows: contact.addressList.map((a) => Tuple2(a.getFullAddress(), a.type)).toList(), + rows: contact.addressList + .map((a) => Tuple2(a.getFullAddress(), a.type)) + .toList(), editType: ContactSectionType.address, ), /// Job if (contact.hasJob) - ClickableIconRow(icon: StyledIcons.work, value: contact.formattedJob, editType: ContactSectionType.job), + ClickableIconRow( + icon: StyledIcons.work, + value: contact.formattedJob, + editType: ContactSectionType.job), /// BIRTHDAY if (contact.hasBirthday) ClickableIconRow( - icon: StyledIcons.birthday, value: contact.birthday.text, editType: ContactSectionType.birthday), + icon: StyledIcons.birthday, + value: contact.birthday.text, + editType: ContactSectionType.birthday), /// Events MultilineClickableIconRow( icon: StyledIcons.calendar, - rows: contact.eventList.map((d) => Tuple2(DateFormats.google.format(d.date), d.type)).toList(), + rows: contact.eventList + .map((d) => Tuple2(DateFormats.google.format(d.date), d.type)) + .toList(), editType: ContactSectionType.events, - ), + ), /// LINKS if (contact.hasLink) MultilineClickableIconRow( icon: StyledIcons.link, onPressed: _handleLinkPressed, - rows: contact.websiteList.map((a) => Tuple2(a.href, a.type)).toList(), + rows: contact.websiteList + .map((a) => Tuple2(a.href, a.type)) + .toList(), editType: ContactSectionType.websites), /// NOTES if (contact.hasNotes) - ClickableIconRow(icon: StyledIcons.note, value: contact.notes, editType: ContactSectionType.notes), + ClickableIconRow( + icon: StyledIcons.note, + value: contact.notes, + editType: ContactSectionType.notes), /// RELATIONSHIP if (contact.hasRelationship) MultilineClickableIconRow( icon: StyledIcons.relationship, - rows: contact.relationList.map((a) => Tuple2(a.person, a.type)).toList(), + rows: contact.relationList + .map((a) => Tuple2(a.person, a.type)) + .toList(), editType: ContactSectionType.relationship, ), ], diff --git a/flokk_src/lib/views/contact_info/contact_info_header_card.dart b/flokk_src/lib/views/contact_info/contact_info_header_card.dart index 63f731e..aae3268 100644 --- a/flokk_src/lib/views/contact_info/contact_info_header_card.dart +++ b/flokk_src/lib/views/contact_info/contact_info_header_card.dart @@ -35,7 +35,8 @@ class _ContactInfoHeaderCardState extends State { AppTheme theme = context.watch(); List labels = contact.groupList - .map((e) => StyledGroupLabel(icon: null, text: e.name.toUpperCase()).padding( + .map((e) => + StyledGroupLabel(icon: null, text: e.name.toUpperCase()).padding( horizontal: Insets.sm * .5, )) .toList(); @@ -46,7 +47,10 @@ class _ContactInfoHeaderCardState extends State { VSpace(Insets.sm - 1), /// PROFILE PIC - StyledUserAvatar(key: ValueKey(contact.id + contact.profilePic), size: 110, contact: contact), + StyledUserAvatar( + key: ValueKey(contact.id + contact.profilePic), + size: 110, + contact: contact), /// TITLE Row( @@ -56,7 +60,9 @@ class _ContactInfoHeaderCardState extends State { OneLineText(contact.nameFull, style: TextStyles.H1).flexible(), HSpace(Insets.sm * .5), ColorShiftIconBtn( - contact.isStarred ? StyledIcons.starFilled : StyledIcons.starEmpty, + contact.isStarred + ? StyledIcons.starFilled + : StyledIcons.starEmpty, color: contact.isStarred ? theme.accent1 : theme.grey, onPressed: () => handleStarPressed(contact), ), @@ -77,7 +83,8 @@ class SocialIconStrip extends StatelessWidget { final ContactData contact; final bool vtMode; - const SocialIconStrip({Key? key, required this.contact, this.vtMode = false}) : super(key: key); + const SocialIconStrip({Key? key, required this.contact, this.vtMode = false}) + : super(key: key); @override Widget build(BuildContext context) { @@ -86,6 +93,8 @@ class SocialIconStrip extends StatelessWidget { ColorShiftIconBtn(StyledIcons.twitterActive), //StyledIconButton(child: Icon(Icons.contacts)), ]; - return vtMode ? widgets.toColumn(mainAxisSize: MainAxisSize.min) : widgets.toRow(mainAxisSize: MainAxisSize.min); + return vtMode + ? widgets.toColumn(mainAxisSize: MainAxisSize.min) + : widgets.toRow(mainAxisSize: MainAxisSize.min); } } diff --git a/flokk_src/lib/views/contact_info/contact_info_panel.dart b/flokk_src/lib/views/contact_info/contact_info_panel.dart index 8dc5b18..32badd3 100644 --- a/flokk_src/lib/views/contact_info/contact_info_panel.dart +++ b/flokk_src/lib/views/contact_info/contact_info_panel.dart @@ -18,7 +18,9 @@ class ContactInfoPanel extends StatefulWidget { final VoidCallback? onClosePressed; final void Function(String?) onEditPressed; - const ContactInfoPanel({Key? key, this.onClosePressed, required this.onEditPressed}) : super(key: key); + const ContactInfoPanel( + {Key? key, this.onClosePressed, required this.onEditPressed}) + : super(key: key); @override ContactInfoPanelState createState() => ContactInfoPanelState(); @@ -56,10 +58,15 @@ class ContactInfoPanelState extends State { children: [ /// TOP ICON ROW Row(children: [ - ColorShiftIconBtn(StyledIcons.closeLarge, size: 16, color: theme.grey, onPressed: widget.onClosePressed), + ColorShiftIconBtn(StyledIcons.closeLarge, + size: 16, + color: theme.grey, + onPressed: widget.onClosePressed), Spacer(), ColorShiftIconBtn(StyledIcons.edit, - size: 22, color: theme.accent1Dark, onPressed: () => widget.onEditPressed("")), + size: 22, + color: theme.accent1Dark, + onPressed: () => widget.onEditPressed("")), ]).padding(horizontal: Insets.l), /// CONTENT STACK @@ -71,25 +78,22 @@ class ContactInfoPanelState extends State { duration: (value == 0 ? 0 : .35).seconds, child: StyledScrollView( child: Column( - children: [ VSpace(2), + /// HEADER CARD ContactInfoHeaderCard(), VSpace(Insets.l), - /// INFO & SOCIAL _DetailsAndSocialTabView( onEditPressed: widget.onEditPressed, - ), + ), ], - ).padding(horizontal: Insets.l), - ), + ).padding(horizontal: Insets.l), ), - ).flexible(), - - + ), + ).flexible(), ], ); }, @@ -100,13 +104,16 @@ class ContactInfoPanelState extends State { class _DetailsAndSocialTabView extends StatefulWidget { final void Function(String?) onEditPressed; - const _DetailsAndSocialTabView({Key? key, required this.onEditPressed}) : super(key: key); + const _DetailsAndSocialTabView({Key? key, required this.onEditPressed}) + : super(key: key); @override - _DetailsAndSocialTabViewState createState() => _DetailsAndSocialTabViewState(); + _DetailsAndSocialTabViewState createState() => + _DetailsAndSocialTabViewState(); } -class _DetailsAndSocialTabViewState extends State<_DetailsAndSocialTabView> with SingleTickerProviderStateMixin { +class _DetailsAndSocialTabViewState extends State<_DetailsAndSocialTabView> + with SingleTickerProviderStateMixin { late TabController tabController; void _handleTabPressed(int i) { @@ -131,7 +138,10 @@ class _DetailsAndSocialTabViewState extends State<_DetailsAndSocialTabView> with @override Widget build(BuildContext context) { // Use .select to bind to the AppModel when showSocialTabOnInfoView changes - int index = context.select((model) => model.showSocialTabOnInfoView) ? 1 : 0; + int index = + context.select((model) => model.showSocialTabOnInfoView) + ? 1 + : 0; return Column( children: [ StyledTabBar( diff --git a/flokk_src/lib/views/contact_info/contact_info_social_card.dart b/flokk_src/lib/views/contact_info/contact_info_social_card.dart index cfe8c94..f9f5207 100644 --- a/flokk_src/lib/views/contact_info/contact_info_social_card.dart +++ b/flokk_src/lib/views/contact_info/contact_info_social_card.dart @@ -35,12 +35,19 @@ class _ContactInfoSocialCardState extends State { ContactData contact = context.watch(); ContactsModel contactsModel = context.watch(); bool isGitLoading = context.select((gm) => gm.isLoading); - bool isTwitterLoading = context.select((tm) => tm.isLoading); + bool isTwitterLoading = + context.select((tm) => tm.isLoading); SocialContactData social = contactsModel.getSocialById(contact.id); int maxItems = 30; - final gitItems = social.gitEvents.map((event) => GitEventListItem(event)).take(maxItems).toList(); - final tweetItems = social.tweets.map((tweet) => TweetListItem(tweet)).take(maxItems).toList(); + final gitItems = social.gitEvents + .map((event) => GitEventListItem(event)) + .take(maxItems) + .toList(); + final tweetItems = social.tweets + .map((tweet) => TweetListItem(tweet)) + .take(maxItems) + .toList(); //return Container(); return Column( diff --git a/flokk_src/lib/views/contact_page/bulk_contact_edit_bar.dart b/flokk_src/lib/views/contact_page/bulk_contact_edit_bar.dart index a7583dd..ffa9e06 100644 --- a/flokk_src/lib/views/contact_page/bulk_contact_edit_bar.dart +++ b/flokk_src/lib/views/contact_page/bulk_contact_edit_bar.dart @@ -17,7 +17,10 @@ class BulkContactEditBar extends StatefulWidget { final VoidCallback? onCheckChanged; const BulkContactEditBar( - {Key? key, this.checked = const [], this.onCheckChanged, this.all = const []}) + {Key? key, + this.checked = const [], + this.onCheckChanged, + this.all = const []}) : super(key: key); @override @@ -38,7 +41,8 @@ class _BulkContactEditBarState extends State { void _handleDeletePressed() async { //Make a copy of the list, so it doesn't get cleared while the Command is still working List usersToDelete = widget.checked.toList(); - await DeleteContactCommand(context).execute(usersToDelete, onDeleteConfirmed: () { + await DeleteContactCommand(context).execute(usersToDelete, + onDeleteConfirmed: () { // For a nicer UI interaction, we want to clear the list immediately when the User has confirmed their delete intent. widget.checked.clear(); widget.onCheckChanged?.call(); @@ -48,7 +52,8 @@ class _BulkContactEditBarState extends State { @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - TextStyle linkStyle = TextStyles.Body2.textHeight(1.1).textColor(theme.accent1); + TextStyle linkStyle = + TextStyles.Body2.textHeight(1.1).textColor(theme.accent1); return StyledContainer( theme.bg1, height: 48, @@ -61,18 +66,27 @@ class _BulkContactEditBarState extends State { HSpace(Insets.m), Text("Select", style: TextStyles.H2.textHeight(1)), HSpace(Insets.sm * 1.5), - TransparentTextBtn("All", style: linkStyle, onPressed: () => _handleCheckChanged(StyledCheckboxValue.All)), - Text(" / ", style: linkStyle).translate(offset: Offset(-Insets.sm, 0)), - TransparentTextBtn("None", style: linkStyle, onPressed: () => _handleCheckChanged(StyledCheckboxValue.None)) + TransparentTextBtn("All", + style: linkStyle, + onPressed: () => _handleCheckChanged(StyledCheckboxValue.All)), + Text(" / ", style: linkStyle) + .translate(offset: Offset(-Insets.sm, 0)), + TransparentTextBtn("None", + style: linkStyle, + onPressed: () => + _handleCheckChanged(StyledCheckboxValue.None)) .translate(offset: Offset(-Insets.sm * 2, 0)), HSpace(Insets.m), //TODO: Implement ManageLabels btn // TransparentIconAndTextBtn("Manage Labels", StyledIcons.label, style: linkStyle), // HSpace(Insets.m), TransparentIconAndTextBtn("Delete", StyledIcons.trash, - style: linkStyle.textColor(theme.grey), onPressed: _handleDeletePressed, color: theme.grey), + style: linkStyle.textColor(theme.grey), + onPressed: _handleDeletePressed, + color: theme.grey), Spacer(), - Text("${widget.checked.length} Selected", style: TextStyles.H2.textColor(theme.grey)), + Text("${widget.checked.length} Selected", + style: TextStyles.H2.textColor(theme.grey)), HSpace(Insets.l), ], ), @@ -81,7 +95,8 @@ class _BulkContactEditBarState extends State { StyledCheckboxValue _getValue() { if (widget.checked.isEmpty) return StyledCheckboxValue.None; - if (widget.checked.length == widget.all.length) return StyledCheckboxValue.All; + if (widget.checked.length == widget.all.length) + return StyledCheckboxValue.All; return StyledCheckboxValue.Partial; } } diff --git a/flokk_src/lib/views/contact_page/contacts_list_row.dart b/flokk_src/lib/views/contact_page/contacts_list_row.dart index 2487782..e9c42bd 100644 --- a/flokk_src/lib/views/contact_page/contacts_list_row.dart +++ b/flokk_src/lib/views/contact_page/contacts_list_row.dart @@ -55,8 +55,10 @@ class _ContactsListRowState extends State { Widget build(BuildContext context) => ContactListCardView(this); } -class ContactListCardView extends WidgetView { - const ContactListCardView(_ContactsListRowState state, {Key? key}) : super(state, key: key); +class ContactListCardView + extends WidgetView { + const ContactListCardView(_ContactsListRowState state, {Key? key}) + : super(state, key: key); ContactData get contact => widget.contact; @@ -85,7 +87,9 @@ class ContactListCardView extends WidgetView 1000) colCount = 4; if (width > 1300) colCount = 5; - TextStyle textStyle = !headerMode ? TextStyles.Body1.size(15) : TextStyles.H2.copyWith(color: theme.greyStrong); + TextStyle textStyle = !headerMode + ? TextStyles.Body1.size(15) + : TextStyles.H2.copyWith(color: theme.greyStrong); Widget rowText(String value) => OneLineText(value, style: textStyle); Widget btn = BaseStyledBtn( @@ -99,11 +103,15 @@ class ContactListCardView extends WidgetView[ /// DIVIDERS - Top and Bottom - if (!headerMode && widget.showDividers) Container(width: double.infinity, height: 1, color: theme.bg1), + if (!headerMode && widget.showDividers) + Container(width: double.infinity, height: 1, color: theme.bg1), if (headerMode) Align( alignment: Alignment.bottomLeft, - child: Container(width: double.infinity, height: 1, color: theme.grey.withOpacity(.6)), + child: Container( + width: double.infinity, + height: 1, + color: theme.grey.withOpacity(.6)), ), Row( //mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -114,7 +122,8 @@ class ContactListCardView extends WidgetView _handleRowChecked(context, value), + onChecked: (value) => + _handleRowChecked(context, value), )) .constrained(minWidth: 300) .expanded(flex: 20 * 100), @@ -123,7 +132,9 @@ class ContactListCardView extends WidgetView 1, flex: 10, - child: headerMode ? rowText("Social") : ClickableSocialBadges(contact, showTimeSince: false), + child: headerMode + ? rowText("Social") + : ClickableSocialBadges(contact, showTimeSince: false), ), /// Phone @@ -144,7 +155,8 @@ class ContactListCardView extends WidgetView 4, flex: 16, - child: rowText(headerMode ? "Job / Company" : contact.jobCompany), + child: + rowText(headerMode ? "Job / Company" : contact.jobCompany), ), //SizedBox(width: Insets.m), @@ -154,8 +166,12 @@ class ContactListCardView extends WidgetView _ProfileCheckboxWithLabelsState(); + _ProfileCheckboxWithLabelsState createState() => + _ProfileCheckboxWithLabelsState(); } -class _ProfileCheckboxWithLabelsState extends State<_ProfileCheckboxWithLabels> { +class _ProfileCheckboxWithLabelsState + extends State<_ProfileCheckboxWithLabels> { @override Widget build(BuildContext context) { double size = 42; @@ -199,9 +219,12 @@ class _ProfileCheckboxWithLabelsState extends State<_ProfileCheckboxWithLabels> ], ); }, - ).gestures(onTapUp: (d) => widget.onChecked(!widget.isChecked), behavior: HitTestBehavior.opaque), + ).gestures( + onTapUp: (d) => widget.onChecked(!widget.isChecked), + behavior: HitTestBehavior.opaque), SizedBox(width: Insets.m), - OneLineText(widget.contact.nameFull, style: TextStyles.Body1.size(15)).expanded(), + OneLineText(widget.contact.nameFull, style: TextStyles.Body1.size(15)) + .expanded(), ], ); } @@ -211,7 +234,11 @@ class _ProfileCheckboxWithLabelsState extends State<_ProfileCheckboxWithLabels> width: size, height: size, alignment: Alignment.center, - child: StyledCheckbox(size: 18, value: widget.isChecked ? StyledCheckboxValue.All : StyledCheckboxValue.None), + child: StyledCheckbox( + size: 18, + value: widget.isChecked + ? StyledCheckboxValue.All + : StyledCheckboxValue.None), ); } } @@ -222,7 +249,12 @@ class _FadingFlexContent extends StatelessWidget { final bool isVisible; final bool enableAnimations; - const _FadingFlexContent({Key? key, this.child, required this.flex, this.isVisible = true, this.enableAnimations = true}) + const _FadingFlexContent( + {Key? key, + this.child, + required this.flex, + this.isVisible = true, + this.enableAnimations = true}) : super(key: key); @override @@ -232,11 +264,14 @@ class _FadingFlexContent extends StatelessWidget { if (enableAnimations) { return TweenAnimationBuilder( curve: !isVisible ? Curves.easeOut : Curves.easeIn, - tween: Tween(begin: isVisible ? 1 : 0, end: isVisible ? 1 : 0), + tween: + Tween(begin: isVisible ? 1 : 0, end: isVisible ? 1 : 0), duration: (isVisible ? .5 : .2).seconds, builder: (_, value, child) { if (value == 0 && !isVisible || child == null) return Container(); - return child.opacity(value).expanded(flex: (targetFlex * value).round()); + return child + .opacity(value) + .expanded(flex: (targetFlex * value).round()); // }, child: Container(child: child, alignment: Alignment.centerLeft)); diff --git a/flokk_src/lib/views/contact_page/contacts_list_with_headers.dart b/flokk_src/lib/views/contact_page/contacts_list_with_headers.dart index 16a9030..3cf2ee2 100644 --- a/flokk_src/lib/views/contact_page/contacts_list_with_headers.dart +++ b/flokk_src/lib/views/contact_page/contacts_list_with_headers.dart @@ -31,7 +31,8 @@ class ContactsListWithHeaders extends StatefulWidget { }) : super(key: key); @override - _ContactsListWithHeadersState createState() => _ContactsListWithHeadersState(); + _ContactsListWithHeadersState createState() => + _ContactsListWithHeadersState(); } class _ContactsListWithHeadersState extends State { @@ -40,14 +41,17 @@ class _ContactsListWithHeadersState extends State { List get checked => widget.checkedContacts; bool _getIsChecked(String id) { - ContactData c = widget.checkedContacts.firstWhere((_c) => _c.id == id, orElse: () => ContactData()); + ContactData c = widget.checkedContacts + .firstWhere((_c) => _c.id == id, orElse: () => ContactData()); return c != ContactData(); } Tuple2, int> getSortedContactsWithFavoriteCount() { - List starred = widget.contacts.toList()..removeWhere((element) => !element.isStarred); + List starred = widget.contacts.toList() + ..removeWhere((element) => !element.isStarred); int starCount = starred.length; - List nonStarred = widget.contacts.toList()..removeWhere((element) => element.isStarred); + List nonStarred = widget.contacts.toList() + ..removeWhere((element) => element.isStarred); return Tuple2(starred..addAll({...nonStarred}), starCount); } @@ -56,7 +60,8 @@ class _ContactsListWithHeadersState extends State { AppTheme theme = context.watch(); return LayoutBuilder( builder: (_, constraints) { - Tuple2, int> contactsWithFavCount = getSortedContactsWithFavoriteCount(); + Tuple2, int> contactsWithFavCount = + getSortedContactsWithFavoriteCount(); List contacts = contactsWithFavCount.item1; int favCount = contactsWithFavCount.item2; @@ -67,30 +72,38 @@ class _ContactsListWithHeadersState extends State { Column( children: [ /// Header: Pass an empty contact, the renderer will switch to header mode - ContactsListRow(ContactData(), parentWidth: constraints.maxWidth) + ContactsListRow(ContactData(), + parentWidth: constraints.maxWidth) .constrained(height: 48) .padding(right: Insets.lGutter - Insets.sm), /// List StyledListView( itemExtent: 78, - itemCount: widget.contacts.length + (favCount == 0 || favCount == widget.contacts.length ? 1 : 2), + itemCount: widget.contacts.length + + (favCount == 0 || favCount == widget.contacts.length + ? 1 + : 2), itemBuilder: (context, i) { /// Inject 1 or 2 header rows into the results bool isFirstHeader = i == 0; bool isSecondHeader = i == favCount + 1 && favCount != 0; - if (isFirstHeader || (isSecondHeader && !widget.searchMode)) { + if (isFirstHeader || + (isSecondHeader && !widget.searchMode)) { String headerText = "SEARCH RESULTS"; int count = contacts.length; if (!widget.searchMode) { bool isFavorite = i == 0 && favCount > 0; - headerText = isFavorite ? "FAVORITE CONTACTS" : "OTHER CONTACTS"; - count = isFavorite ? favCount : contacts.length - favCount; + headerText = + isFavorite ? "FAVORITE CONTACTS" : "OTHER CONTACTS"; + count = + isFavorite ? favCount : contacts.length - favCount; } /// Header text return Container( - child: Text("$headerText ($count)", style: TextStyles.T1.textColor(theme.accent1Dark)), + child: Text("$headerText ($count)", + style: TextStyles.T1.textColor(theme.accent1Dark)), alignment: Alignment.bottomLeft, margin: EdgeInsets.only(bottom: Insets.l + 4), ); diff --git a/flokk_src/lib/views/contact_page/contacts_page.dart b/flokk_src/lib/views/contact_page/contacts_page.dart index fa055dd..0e0f5e3 100644 --- a/flokk_src/lib/views/contact_page/contacts_page.dart +++ b/flokk_src/lib/views/contact_page/contacts_page.dart @@ -18,14 +18,20 @@ class ContactsPage extends StatefulWidget { final List checkedContacts; final ContactData selectedContact; - const ContactsPage({Key? key, required this.searchEngine, this.checkedContacts = const[], required this.selectedContact}) : super(key: key); + const ContactsPage( + {Key? key, + required this.searchEngine, + this.checkedContacts = const [], + required this.selectedContact}) + : super(key: key); @override ContactsPageState createState() => ContactsPageState(); } class ContactsPageState extends State { - Future handleRefreshTriggered() async => await RefreshContactsCommand(context).execute(); + Future handleRefreshTriggered() async => + await RefreshContactsCommand(context).execute(); @override Widget build(BuildContext context) => _ContactsPageView(this); @@ -53,9 +59,11 @@ class _ContactsPageView extends WidgetView { /// Wrap content in PlaceholderSwitcher, which will handle empty results return PlaceholderContentSwitcher( hasContent: () => sorted.isNotEmpty, - placeholder: ContactListPlaceholder(isSearching: widget.searchEngine.hasQuery), + placeholder: ContactListPlaceholder( + isSearching: widget.searchEngine.hasQuery), showOutline: false, - placeholderPadding: EdgeInsets.only(top: Insets.m * 1.5, right: Insets.m, bottom: Insets.m), + placeholderPadding: EdgeInsets.only( + top: Insets.m * 1.5, right: Insets.m, bottom: Insets.m), /// ContactList content: ContactsListWithHeaders( diff --git a/flokk_src/lib/views/dashboard_page/dashboard_page.dart b/flokk_src/lib/views/dashboard_page/dashboard_page.dart index d8abddf..4dd746f 100644 --- a/flokk_src/lib/views/dashboard_page/dashboard_page.dart +++ b/flokk_src/lib/views/dashboard_page/dashboard_page.dart @@ -11,7 +11,8 @@ import 'package:flutter/material.dart'; class DashboardPage extends StatefulWidget { final ContactData selectedContact; - const DashboardPage({Key? key, required this.selectedContact}) : super(key: key); + const DashboardPage({Key? key, required this.selectedContact}) + : super(key: key); @override DashboardPageState createState() => DashboardPageState(); @@ -27,10 +28,14 @@ class DashboardPageState extends State { SizedBox(height: Insets.l), TopContactsSection(), VSpace(Insets.m), - SocialActivitySection().padding(horizontal: Insets.lGutter).flexible(), + SocialActivitySection() + .padding(horizontal: Insets.lGutter) + .flexible(), SizedBox(height: Insets.l * 1.5), RepaintBoundary( - child: UpcomingActivitiesSection().height(170).padding(horizontal: Insets.lGutter), + child: UpcomingActivitiesSection() + .height(170) + .padding(horizontal: Insets.lGutter), ), SizedBox(height: Insets.l), ], diff --git a/flokk_src/lib/views/dashboard_page/dates/important_date_card.dart b/flokk_src/lib/views/dashboard_page/dates/important_date_card.dart index 5a831c4..a198314 100644 --- a/flokk_src/lib/views/dashboard_page/dates/important_date_card.dart +++ b/flokk_src/lib/views/dashboard_page/dates/important_date_card.dart @@ -14,7 +14,8 @@ import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; class ImportantEventCard extends StatelessWidget { - const ImportantEventCard(this.contact, this.event, {Key? key}) : super(key: key); + const ImportantEventCard(this.contact, this.event, {Key? key}) + : super(key: key); static DateFormat get monthDayFmt => DateFormat("MMMMEEEEd"); @@ -30,7 +31,9 @@ class ImportantEventCard extends StatelessWidget { Color eventColor = isBirthday ? theme.accent3 : theme.accent2; return TransparentBtn( - onPressed: () => context.read().trySetSelectedContact(contact, showSocial: false), + onPressed: () => context + .read() + .trySetSelectedContact(contact, showSocial: false), borderRadius: Corners.s8, contentPadding: EdgeInsets.zero, child: StyledCard( @@ -47,9 +50,11 @@ class ImportantEventCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Spacer(), - OneLineText(event.getType(), style: cardContentText.textColor(eventColor)), + OneLineText(event.getType(), + style: cardContentText.textColor(eventColor)), VSpace(Insets.sm), - OneLineText(monthDayFmt.format(event.date), style: cardContentText), + OneLineText(monthDayFmt.format(event.date), + style: cardContentText), Spacer(), ], ).width(110), diff --git a/flokk_src/lib/views/dashboard_page/dates/important_dates_section.dart b/flokk_src/lib/views/dashboard_page/dates/important_dates_section.dart index 217ebbb..d249eb9 100644 --- a/flokk_src/lib/views/dashboard_page/dates/important_dates_section.dart +++ b/flokk_src/lib/views/dashboard_page/dates/important_dates_section.dart @@ -20,11 +20,14 @@ class UpcomingActivitiesSection extends StatelessWidget { Widget build(BuildContext context) { AppTheme theme = context.watch(); ContactsModel contactsModel = context.watch(); - List> contactsWithDate = contactsModel.upcomingDateContacts; + List> contactsWithDate = + contactsModel.upcomingDateContacts; TextStyle headerStyle = TextStyles.T1; /// Create list of ItemRenderers - List kids = contactsWithDate.map((cWithD) => ImportantEventCard(cWithD.item1, cWithD.item2)).toList(); + List kids = contactsWithDate + .map((cWithD) => ImportantEventCard(cWithD.item1, cWithD.item2)) + .toList(); /// Build list return LayoutBuilder( @@ -33,7 +36,8 @@ class UpcomingActivitiesSection extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("UPCOMING IMPORTANT DATES", style: headerStyle.textColor(theme.accent1Darker)), + Text("UPCOMING IMPORTANT DATES", + style: headerStyle.textColor(theme.accent1Darker)), VSpace(Insets.l * .75), PlaceholderContentSwitcher( hasContent: () => kids.isNotEmpty, diff --git a/flokk_src/lib/views/dashboard_page/social/responsive_double_list.dart b/flokk_src/lib/views/dashboard_page/social/responsive_double_list.dart index 9a39140..9a54ab4 100644 --- a/flokk_src/lib/views/dashboard_page/social/responsive_double_list.dart +++ b/flokk_src/lib/views/dashboard_page/social/responsive_double_list.dart @@ -68,13 +68,19 @@ class _ResponsiveDoubleListState extends State { PlaceholderContentSwitcher( hasContent: () => widget.list1.isNotEmpty, placeholder: widget.list1Placeholder, - content: StyledListViewWithTitle(listItems: widget.list1, title: widget.list1Title, icon: widget.list1Icon), + content: StyledListViewWithTitle( + listItems: widget.list1, + title: widget.list1Title, + icon: widget.list1Icon), ).flexible(), HSpace(Insets.l), PlaceholderContentSwitcher( hasContent: () => widget.list2.isNotEmpty, placeholder: widget.list2Placeholder, - content: StyledListViewWithTitle(listItems: widget.list2, title: widget.list2Title, icon: widget.list2Icon), + content: StyledListViewWithTitle( + listItems: widget.list2, + title: widget.list2Title, + icon: widget.list2Icon), ).flexible(), ], ); diff --git a/flokk_src/lib/views/dashboard_page/social/social_activities_section.dart b/flokk_src/lib/views/dashboard_page/social/social_activities_section.dart index 7088ae2..85b0848 100644 --- a/flokk_src/lib/views/dashboard_page/social/social_activities_section.dart +++ b/flokk_src/lib/views/dashboard_page/social/social_activities_section.dart @@ -25,9 +25,15 @@ class SocialActivitySection extends StatefulWidget { class _SocialActivitySectionState extends State { void _handleTabPressed(int index) { - if (index == 0) context.read().dashSocialSection = DashboardSocialSectionType.All; - if (index == 1) context.read().dashSocialSection = DashboardSocialSectionType.Twitter; - if (index == 2) context.read().dashSocialSection = DashboardSocialSectionType.Git; + if (index == 0) + context.read().dashSocialSection = + DashboardSocialSectionType.All; + if (index == 1) + context.read().dashSocialSection = + DashboardSocialSectionType.Twitter; + if (index == 2) + context.read().dashSocialSection = + DashboardSocialSectionType.Git; context.read().scheduleSave(); } @@ -39,13 +45,17 @@ class _SocialActivitySectionState extends State { return LayoutBuilder( builder: (layoutContext, constraints) { /// Responsively size tab bars - double tabWidth = constraints.maxWidth < PageBreaks.LargePhone ? 240 : 280; + double tabWidth = + constraints.maxWidth < PageBreaks.LargePhone ? 240 : 280; TextStyle headerStyle = TextStyles.T1; - bool useTabView = constraints.maxWidth < PageBreaks.TabletPortrait - 100; + bool useTabView = + constraints.maxWidth < PageBreaks.TabletPortrait - 100; /// Determine which tab should be selected - var sectionType = layoutContext.select((model) => model.dashSocialSection); + var sectionType = + layoutContext.select( + (model) => model.dashSocialSection); int tabIndex = 0; if (sectionType == DashboardSocialSectionType.Twitter) tabIndex = 1; if (sectionType == DashboardSocialSectionType.Git) tabIndex = 2; @@ -64,31 +74,51 @@ class _SocialActivitySectionState extends State { switch (sectionType) { case DashboardSocialSectionType.All: list1Title = "TWITTER RECENT ACTIVITY"; - list1 = twitterModel.allTweets.map((tweet) => TweetListItem(tweet)).take(maxItems).toList(); + list1 = twitterModel.allTweets + .map((tweet) => TweetListItem(tweet)) + .take(maxItems) + .toList(); list1Placeholder = TwitterPlaceholder(contact: ContactData()); icon1 = StyledIcons.twitterActive; list2Title = "GITHUB RECENT ACTIVITY"; - list2 = gitModel.allEvents.map((event) => GitEventListItem(event)).take(maxItems).toList(); + list2 = gitModel.allEvents + .map((event) => GitEventListItem(event)) + .take(maxItems) + .toList(); list2Placeholder = GitPlaceholder(contact: ContactData()); icon2 = StyledIcons.githubActive; break; case DashboardSocialSectionType.Git: list1Title = "GITHUB RECENT ACTIVITY"; list1Placeholder = GitPlaceholder(contact: ContactData()); - list1 = gitModel.allEvents.map((event) => GitEventListItem(event)).take(maxItems).toList(); + list1 = gitModel.allEvents + .map((event) => GitEventListItem(event)) + .take(maxItems) + .toList(); icon1 = StyledIcons.githubActive; list2Title = "TRENDING REPOSITORIES"; - list2Placeholder = GitPlaceholder(contact: ContactData(), isTrending: true); - list2 = gitModel.popularRepos.map((repo) => GitRepoListItem(repo)).take(maxItems).toList(); + list2Placeholder = + GitPlaceholder(contact: ContactData(), isTrending: true); + list2 = gitModel.popularRepos + .map((repo) => GitRepoListItem(repo)) + .take(maxItems) + .toList(); icon2 = StyledIcons.githubActive; break; case DashboardSocialSectionType.Twitter: - list1 = twitterModel.allTweets.map((e) => TweetListItem(e)).take(maxItems).toList(); + list1 = twitterModel.allTweets + .map((e) => TweetListItem(e)) + .take(maxItems) + .toList(); list1Placeholder = TwitterPlaceholder(contact: ContactData()); list1Title = "TWITTER RECENT ACTIVITY"; icon1 = StyledIcons.twitterActive; - list2 = twitterModel.popularTweets.map((e) => TweetListItem(e)).take(maxItems).toList(); - list2Placeholder = TwitterPlaceholder(contact: ContactData(), isPopular: true); + list2 = twitterModel.popularTweets + .map((e) => TweetListItem(e)) + .take(maxItems) + .toList(); + list2Placeholder = + TwitterPlaceholder(contact: ContactData(), isPopular: true); list2Title = "POPULAR TWEETS"; icon2 = StyledIcons.twitterActive; break; @@ -100,12 +130,16 @@ class _SocialActivitySectionState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - OneLineText("SOCIAL ACTIVITIES", style: headerStyle.textColor(theme.accent1Darker)).flexible(), + OneLineText("SOCIAL ACTIVITIES", + style: headerStyle.textColor(theme.accent1Darker)) + .flexible(), StyledTabBar( index: tabIndex, sections: ["All", "Twitter", "GitHub"], onTabPressed: _handleTabPressed, - ).constrained(maxWidth: tabWidth, animate: true).animate(Durations.medium, Curves.easeOut), + ) + .constrained(maxWidth: tabWidth, animate: true) + .animate(Durations.medium, Curves.easeOut), ], ), VSpace(Insets.l * .75), diff --git a/flokk_src/lib/views/dashboard_page/social/tabbed_list_view.dart b/flokk_src/lib/views/dashboard_page/social/tabbed_list_view.dart index 888623f..90fec5d 100644 --- a/flokk_src/lib/views/dashboard_page/social/tabbed_list_view.dart +++ b/flokk_src/lib/views/dashboard_page/social/tabbed_list_view.dart @@ -37,7 +37,9 @@ class TabbedListView extends StatelessWidget { this.list1Placeholder, this.list2Placeholder, this.index = 0, - this.onTabPressed, required this.list1Icon, required this.list2Icon}) + this.onTabPressed, + required this.list1Icon, + required this.list2Icon}) : super(key: key); @override @@ -48,7 +50,8 @@ class TabbedListView extends StatelessWidget { ShapeDecoration buildTabDec(bool isBg) { return ShapeDecoration( shape: TabBorder(selectedTab: isBg ? -1 : index, barHeight: barHeight), - color: isBg ? theme.surface : ColorUtils.blend(theme.bg1, theme.bg2, .35), + color: + isBg ? theme.surface : ColorUtils.blend(theme.bg1, theme.bg2, .35), shadows: isBg ? Shadows.m(theme.accent1) : null, ); } @@ -58,7 +61,9 @@ class TabbedListView extends StatelessWidget { return Stack( children: [ /// Tab Bg - Container(decoration: buildTabDec(true), foregroundDecoration: buildTabDec(false)), + Container( + decoration: buildTabDec(true), + foregroundDecoration: buildTabDec(false)), /// Top Row of Btns Row( @@ -89,11 +94,15 @@ class TabbedListView extends StatelessWidget { /// Content Container( child: Container( - margin: EdgeInsets.all(Insets.l).copyWith(right: Insets.m, top: Insets.m * 1.5), + margin: EdgeInsets.all(Insets.l) + .copyWith(right: Insets.m, top: Insets.m * 1.5), child: PlaceholderContentSwitcher( - hasContent: () => firstSelected ? list1.isNotEmpty : list2.isNotEmpty, + hasContent: () => + firstSelected ? list1.isNotEmpty : list2.isNotEmpty, placeholderPadding: EdgeInsets.only(right: Insets.m), - placeholder: (firstSelected ? list1Placeholder : list2Placeholder) ?? Container(), + placeholder: + (firstSelected ? list1Placeholder : list2Placeholder) ?? + Container(), content: StyledListView( itemCount: firstSelected ? list1.length : list2.length, itemBuilder: (_, i) => firstSelected ? list1[i] : list2[i], @@ -114,7 +123,14 @@ class _TransparentTabBtn extends StatelessWidget { final String title; final AssetImage icon; - const _TransparentTabBtn({Key? key, this.isSelected = false, required this.type, this.onPressed, this.height = 0, this.title = "", required this.icon}) + const _TransparentTabBtn( + {Key? key, + this.isSelected = false, + required this.type, + this.onPressed, + this.height = 0, + this.title = "", + required this.icon}) : super(key: key); @override @@ -157,16 +173,24 @@ class TabBorder extends ShapeBorder { var radius = Radius.circular(8); void drawBody(Path p) { - Rect tabRect = Rect.fromLTWH(rect.left, rect.top + barHeight, rect.width, rect.height - barHeight); + Rect tabRect = Rect.fromLTWH( + rect.left, rect.top + barHeight, rect.width, rect.height - barHeight); p.addRRect(RRect.fromRectAndCorners(tabRect, - topLeft: Radius.zero, bottomLeft: radius, topRight: Radius.zero, bottomRight: radius)); + topLeft: Radius.zero, + bottomLeft: radius, + topRight: Radius.zero, + bottomRight: radius)); } void drawTab(Path p, bool rightSide) { double xPos = rightSide ? rect.width * .5 : 0; - Rect tabRect = Rect.fromLTWH(rect.left + xPos, rect.top, rect.width * .5, barHeight); + Rect tabRect = + Rect.fromLTWH(rect.left + xPos, rect.top, rect.width * .5, barHeight); p.addRRect(RRect.fromRectAndCorners(tabRect, - topLeft: radius, bottomLeft: Radius.zero, topRight: radius, bottomRight: Radius.zero)); + topLeft: radius, + bottomLeft: Radius.zero, + topRight: radius, + bottomRight: Radius.zero)); } //Bg mode draws 2 tabs and a body section. Otherwise, just the un-selected tab is drawn. diff --git a/flokk_src/lib/views/dashboard_page/top/small_contact_card.dart b/flokk_src/lib/views/dashboard_page/top/small_contact_card.dart index 08cd4e0..29dbe62 100644 --- a/flokk_src/lib/views/dashboard_page/top/small_contact_card.dart +++ b/flokk_src/lib/views/dashboard_page/top/small_contact_card.dart @@ -12,15 +12,15 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class SmallContactCard extends StatelessWidget { - static const double cardWidth = 162; final ContactData contact; const SmallContactCard(this.contact, {Key? key}) : super(key: key); - void _handleCardPressed(BuildContext c) => - c.read().trySetSelectedContact(contact, showSocial: false); + void _handleCardPressed(BuildContext c) => c + .read() + .trySetSelectedContact(contact, showSocial: false); @override Widget build(BuildContext context) { diff --git a/flokk_src/lib/views/dashboard_page/top/top_contacts_section.dart b/flokk_src/lib/views/dashboard_page/top/top_contacts_section.dart index 9d68f35..872652e 100644 --- a/flokk_src/lib/views/dashboard_page/top/top_contacts_section.dart +++ b/flokk_src/lib/views/dashboard_page/top/top_contacts_section.dart @@ -25,8 +25,9 @@ class TopContactsSection extends StatefulWidget { class _TopContactsSectionState extends State { void _handleTabPressed(int index) { - context.read().dashContactsSection = - index == 0 ? DashboardContactsSectionType.Favorites : DashboardContactsSectionType.RecentlyActive; + context.read().dashContactsSection = index == 0 + ? DashboardContactsSectionType.Favorites + : DashboardContactsSectionType.RecentlyActive; context.read().scheduleSave(); } @@ -36,7 +37,8 @@ class _TopContactsSectionState extends State { ContactsModel contactsModel = context.watch(); /// Bind to section type on AppModel - var sectionType = context.select((model) => model.dashContactsSection); + var sectionType = context.select( + (model) => model.dashContactsSection); int tabIndex = 0; if (sectionType == DashboardContactsSectionType.RecentlyActive) { tabIndex = 1; @@ -45,10 +47,14 @@ class _TopContactsSectionState extends State { /// Use a layout builder so we can size this view responsively when the panel slides out return LayoutBuilder( builder: (_, constraints) { - List contacts = sectionType == DashboardContactsSectionType.Favorites - ? contactsModel.starred - : contactsModel.mostRecentSocialContacts.map((e) => e.contact).toList(); - double tabWidth = constraints.maxWidth < PageBreaks.LargePhone ? 240 : 280; + List contacts = + sectionType == DashboardContactsSectionType.Favorites + ? contactsModel.starred + : contactsModel.mostRecentSocialContacts + .map((e) => e.contact) + .toList(); + double tabWidth = + constraints.maxWidth < PageBreaks.LargePhone ? 240 : 280; TextStyle headerStyle = TextStyles.T1; double cardHeight = 208; @@ -59,12 +65,16 @@ class _TopContactsSectionState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - OneLineText("CONTACTS", style: headerStyle.textColor(theme.accent1Darker)).flexible(), + OneLineText("CONTACTS", + style: headerStyle.textColor(theme.accent1Darker)) + .flexible(), StyledTabBar( index: tabIndex, sections: ["Favorites", "Recently Active"], onTabPressed: _handleTabPressed, - ).constrained(maxWidth: tabWidth, animate: true).animate(Durations.medium, Curves.easeOut), + ) + .constrained(maxWidth: tabWidth, animate: true) + .animate(Durations.medium, Curves.easeOut), ], ).padding(horizontal: Insets.lGutter), VSpace(Insets.sm), @@ -73,8 +83,11 @@ class _TopContactsSectionState extends State { FadingIndexedStack( index: tabIndex, children: [ - _ContactCardList(this, contacts: contacts, placeholder: TopContactsPlaceholder()), - _ContactCardList(this, contacts: contacts, placeholder: TopContactsPlaceholder(isRecent: true)), + _ContactCardList(this, + contacts: contacts, placeholder: TopContactsPlaceholder()), + _ContactCardList(this, + contacts: contacts, + placeholder: TopContactsPlaceholder(isRecent: true)), ], ).height(cardHeight + Insets.m * 2), ], @@ -89,12 +102,17 @@ class _ContactCardList extends StatelessWidget { final List contacts; final Widget placeholder; - const _ContactCardList(this.state, {Key? key, this.contacts = const[], required this.placeholder}) : super(key: key); + const _ContactCardList(this.state, + {Key? key, + this.contacts = const [], + required this.placeholder}) + : super(key: key); @override Widget build(BuildContext context) { /// Layout content - EdgeInsets padding = EdgeInsets.symmetric(horizontal: Insets.l, vertical: Insets.m); + EdgeInsets padding = + EdgeInsets.symmetric(horizontal: Insets.l, vertical: Insets.m); // Placeholder content-box return PlaceholderContentSwitcher( hasContent: () => contacts.isNotEmpty, diff --git a/flokk_src/lib/views/empty_states/placeholder_contact_list.dart b/flokk_src/lib/views/empty_states/placeholder_contact_list.dart index 5c4a5b9..dff9326 100644 --- a/flokk_src/lib/views/empty_states/placeholder_contact_list.dart +++ b/flokk_src/lib/views/empty_states/placeholder_contact_list.dart @@ -1,4 +1,3 @@ - import 'package:flokk/_internal/components/spacing.dart'; import 'package:flokk/app_extensions.dart'; import 'package:flokk/styles.dart'; @@ -10,28 +9,32 @@ import 'package:provider/provider.dart'; class ContactListPlaceholder extends StatelessWidget { final bool isSearching; - const ContactListPlaceholder({Key? key, this.isSearching = false}) : super(key: key); + const ContactListPlaceholder({Key? key, this.isSearching = false}) + : super(key: key); @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - var bgImage = Image.asset("assets/images/empty-noresult-bg@2x.png", height: 108, color: theme.bg2) + var bgImage = Image.asset("assets/images/empty-noresult-bg@2x.png", + height: 108, color: theme.bg2) .translate(offset: Offset(8, 2)); return Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - PlaceholderImageAndBgStack("noresult-owl", bgWidget: bgImage, height: 126, top: 15, left: -30), + PlaceholderImageAndBgStack("noresult-owl", + bgWidget: bgImage, height: 126, top: 15, left: -30), VSpace(Insets.l), isSearching - ? EmptyStateTitleAndClickableText( - title: "NO RESULTS IN YOUR CONTACTS", - startText: "We couldn't find any results that matched your search.\nPlease try another search.", - ) - : EmptyStateTitleAndClickableText( - onPressed: () => showContactPage(context), - title: "NO CONTACTS YET", - startText: "", - linkText: "Create Contacts", - endText: " to get started!", - ) + ? EmptyStateTitleAndClickableText( + title: "NO RESULTS IN YOUR CONTACTS", + startText: + "We couldn't find any results that matched your search.\nPlease try another search.", + ) + : EmptyStateTitleAndClickableText( + onPressed: () => showContactPage(context), + title: "NO CONTACTS YET", + startText: "", + linkText: "Create Contacts", + endText: " to get started!", + ) ]); } } diff --git a/flokk_src/lib/views/empty_states/placeholder_content_switcher.dart b/flokk_src/lib/views/empty_states/placeholder_content_switcher.dart index 7ee476d..df7feff 100644 --- a/flokk_src/lib/views/empty_states/placeholder_content_switcher.dart +++ b/flokk_src/lib/views/empty_states/placeholder_content_switcher.dart @@ -30,7 +30,7 @@ class PlaceholderContentSwitcher extends StatelessWidget { return Stack( fit: StackFit.expand, children: [ - hasContent()? content : _buildPlaceholder(context), + hasContent() ? content : _buildPlaceholder(context), ], ); } diff --git a/flokk_src/lib/views/empty_states/placeholder_git.dart b/flokk_src/lib/views/empty_states/placeholder_git.dart index 7d6a6fe..d3ba7b4 100644 --- a/flokk_src/lib/views/empty_states/placeholder_git.dart +++ b/flokk_src/lib/views/empty_states/placeholder_git.dart @@ -1,4 +1,3 @@ - import 'package:flokk/data/contact_data.dart'; import 'package:flokk/views/contact_edit/contact_edit_panel.dart'; import 'package:flokk/views/empty_states/placeholder_widget_helpers.dart'; @@ -10,7 +9,9 @@ class GitPlaceholder extends StatelessWidget { // If contact is set, this widget will act as if it belongs to a single contact final ContactData contact; - const GitPlaceholder({Key? key, this.isTrending = false, required this.contact}) : super(key: key); + const GitPlaceholder( + {Key? key, this.isTrending = false, required this.contact}) + : super(key: key); void _handleLinkPressed(BuildContext context) { //If in single-contact mode, try and edit the selected contact @@ -26,16 +27,20 @@ class GitPlaceholder extends StatelessWidget { @override Widget build(BuildContext context) { return LayoutBuilder( - builder: (_, constraints) => Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - if (constraints.maxHeight > 250) PlaceholderImageAndBgStack("dashboard-github", height: 126, top: 43, left: -30), + builder: (_, constraints) => + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + if (constraints.maxHeight > 250) + PlaceholderImageAndBgStack("dashboard-github", + height: 126, top: 43, left: -30), EmptyStateTitleAndClickableText( title: isTrending ? "NO TRENDING REPOS" : "NO GITHUB ACTIVITY", startText: contact == ContactData() ? "Add GitHub ID in " : "Add ", linkText: contact == ContactData() ? "contacts" : "GitHub ID", - endText: " to show ${isTrending ? "trending repos" : "recent activity"}", + endText: + " to show ${isTrending ? "trending repos" : "recent activity"}", onPressed: () => _handleLinkPressed(context), - ), + ), ]), - ); + ); } } diff --git a/flokk_src/lib/views/empty_states/placeholder_important_dates.dart b/flokk_src/lib/views/empty_states/placeholder_important_dates.dart index 3d6f47b..1d8c04d 100644 --- a/flokk_src/lib/views/empty_states/placeholder_important_dates.dart +++ b/flokk_src/lib/views/empty_states/placeholder_important_dates.dart @@ -11,7 +11,7 @@ class ImportantDatesPlaceholder extends StatelessWidget { title: "NO UPCOMING IMPORTANT DATES", startText: "Add birthdays/special dates to your ", linkText: "contacts", - onPressed: ()=>showContactPage(context), + onPressed: () => showContactPage(context), ), ], ); diff --git a/flokk_src/lib/views/empty_states/placeholder_top_contacts.dart b/flokk_src/lib/views/empty_states/placeholder_top_contacts.dart index f0db616..a5d8a4d 100644 --- a/flokk_src/lib/views/empty_states/placeholder_top_contacts.dart +++ b/flokk_src/lib/views/empty_states/placeholder_top_contacts.dart @@ -8,8 +8,8 @@ import 'package:flutter/material.dart'; class TopContactsPlaceholder extends StatelessWidget { final bool isRecent; - const TopContactsPlaceholder({Key? key, this.isRecent = false}) : super(key: key); - + const TopContactsPlaceholder({Key? key, this.isRecent = false}) + : super(key: key); @override Widget build(BuildContext context) { @@ -22,17 +22,22 @@ class TopContactsPlaceholder extends StatelessWidget { children: [ if (showImage) ...{ isRecent - ? PlaceholderImageAndBgStack("dashboard-recentActive", height: 157, top: 2) - : PlaceholderImageAndBgStack("dashboard-favorites", height: 126, top: 22), + ? PlaceholderImageAndBgStack("dashboard-recentActive", + height: 157, top: 2) + : PlaceholderImageAndBgStack("dashboard-favorites", + height: 126, top: 22), HSpace(Insets.xl), }, EmptyStateTitleAndClickableText( title: isRecent ? "NO RECENT ACTIVITY" : "NO FAVORITE CONTACTS", - startText: "${isRecent ? "Add GitHub and Twitter handles in " : "Star "}", + startText: + "${isRecent ? "Add GitHub and Twitter handles in " : "Star "}", linkText: "contacts", endText: " to show their recent activity", onPressed: () => showContactPage(context), - crossAxisAlign: showImage ? CrossAxisAlignment.start : CrossAxisAlignment.center, + crossAxisAlign: showImage + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, ).width(230).translate(offset: Offset(0, -15)) ], ); diff --git a/flokk_src/lib/views/empty_states/placeholder_twitter.dart b/flokk_src/lib/views/empty_states/placeholder_twitter.dart index 2b2b6e0..d91a0ec 100644 --- a/flokk_src/lib/views/empty_states/placeholder_twitter.dart +++ b/flokk_src/lib/views/empty_states/placeholder_twitter.dart @@ -10,7 +10,9 @@ class TwitterPlaceholder extends StatelessWidget { // If contact is set, this widget will act as if it belongs to a single contact final ContactData contact; - const TwitterPlaceholder({Key? key, this.isPopular = false, required this.contact}) : super(key: key); + const TwitterPlaceholder( + {Key? key, this.isPopular = false, required this.contact}) + : super(key: key); void _handleLinkPressed(BuildContext context) { //If in single-contact mode, try and edit the selected contact @@ -26,13 +28,17 @@ class TwitterPlaceholder extends StatelessWidget { @override Widget build(BuildContext context) { return LayoutBuilder( - builder: (_, constraints) => Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - if (constraints.maxHeight > 250) PlaceholderImageAndBgStack("dashboard-twitter", height: 126, top: 43), + builder: (_, constraints) => + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + if (constraints.maxHeight > 250) + PlaceholderImageAndBgStack("dashboard-twitter", height: 126, top: 43), EmptyStateTitleAndClickableText( title: isPopular ? "NO POPULAR TWEETS" : "NO TWITTER ACTIVITY", - startText: contact == ContactData() ? "Add Twitter Handles in " : "Add ", + startText: + contact == ContactData() ? "Add Twitter Handles in " : "Add ", linkText: contact == ContactData() ? "contacts" : "Twitter Handle", - endText: " to show ${isPopular ? "popular tweets" : "recent activity"}", + endText: + " to show ${isPopular ? "popular tweets" : "recent activity"}", onPressed: () => _handleLinkPressed(context), ), ]), diff --git a/flokk_src/lib/views/empty_states/placeholder_widget_helpers.dart b/flokk_src/lib/views/empty_states/placeholder_widget_helpers.dart index 1b38188..8e557c9 100644 --- a/flokk_src/lib/views/empty_states/placeholder_widget_helpers.dart +++ b/flokk_src/lib/views/empty_states/placeholder_widget_helpers.dart @@ -37,7 +37,10 @@ class EmptyStateTitleAndClickableText extends StatelessWidget { }) : super(key: key); TextSpan _buildTapSpan(String text, TextStyle style, VoidCallback? handler) { - return TextSpan(text: text, style: style, recognizer: TapGestureRecognizer()..onTap = handler); + return TextSpan( + text: text, + style: style, + recognizer: TapGestureRecognizer()..onTap = handler); } @override @@ -59,7 +62,9 @@ class EmptyStateTitleAndClickableText extends StatelessWidget { style: style, children: [ if (StringUtils.isNotEmpty(startText)) TextSpan(text: startText), - if (StringUtils.isNotEmpty(linkText)) _buildTapSpan(linkText, style.textColor(theme.accent1), onPressed), + if (StringUtils.isNotEmpty(linkText)) + _buildTapSpan( + linkText, style.textColor(theme.accent1), onPressed), if (StringUtils.isNotEmpty(endText)) TextSpan(text: endText), ], ), @@ -90,7 +95,8 @@ class PlaceholderImageAndBgStack extends StatelessWidget { Positioned( left: left, top: top, - child: Image.asset("assets/images/empty-$path@2x.png", height: height), + child: + Image.asset("assets/images/empty-$path@2x.png", height: height), ) ], ); @@ -101,6 +107,7 @@ class _BgCircle extends StatelessWidget { @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - return StyledContainer(theme.bg2, width: 157, height: 157, borderRadius: BorderRadius.circular(999)); + return StyledContainer(theme.bg2, + width: 157, height: 157, borderRadius: BorderRadius.circular(999)); } } diff --git a/flokk_src/lib/views/main_scaffold/contact_panel.dart b/flokk_src/lib/views/main_scaffold/contact_panel.dart index d84fd9b..24a7031 100644 --- a/flokk_src/lib/views/main_scaffold/contact_panel.dart +++ b/flokk_src/lib/views/main_scaffold/contact_panel.dart @@ -15,7 +15,9 @@ class ContactPanel extends StatefulWidget { final VoidCallback? onClosePressed; final ContactsModel contactsModel; - const ContactPanel({Key? key, this.onClosePressed, required this.contactsModel}) : super(key: key); + const ContactPanel( + {Key? key, this.onClosePressed, required this.contactsModel}) + : super(key: key); @override ContactPanelState createState() => ContactPanelState(); @@ -30,7 +32,8 @@ class ContactPanelState extends State { String _initialEditSection = ""; - bool get hasUnsavedChanged => _isEditingContact && (editKey?.currentState?.isDirty ?? false); + bool get hasUnsavedChanged => + _isEditingContact && (editKey?.currentState?.isDirty ?? false); void showEditView(String sectionType) { _initialEditSection = sectionType; @@ -41,7 +44,8 @@ class ContactPanelState extends State { setState(() => _isEditingContact = false); } - void _handleEditPressed(String? startSection) => showEditView(startSection ?? ""); + void _handleEditPressed(String? startSection) => + showEditView(startSection ?? ""); void _handleEditComplete(ContactData contact) { /// If contact is not null, then we want to switch back to the InfoView @@ -71,8 +75,7 @@ class ContactPanelState extends State { /// When contact has been set to null, we want to use the prevContact so we get a clean transition out /// Bit of a hack, but not sure how else to maintain state as we slide out. - if (contact == ContactData()) - contact = _prevContact ?? ContactData(); + if (contact == ContactData()) contact = _prevContact ?? ContactData(); if (contact != ContactData()) _prevContact = contact; /// Anytime we're working on a new contact, we want to be in edit mode diff --git a/flokk_src/lib/views/main_scaffold/light_dark_toggle_switch.dart b/flokk_src/lib/views/main_scaffold/light_dark_toggle_switch.dart index 225eb13..0ea92c7 100644 --- a/flokk_src/lib/views/main_scaffold/light_dark_toggle_switch.dart +++ b/flokk_src/lib/views/main_scaffold/light_dark_toggle_switch.dart @@ -19,7 +19,8 @@ class _LightDarkToggleSwitchState extends State { int lastSwitchTime = 0; void _handleTogglePressed(BuildContext context) { - if (DateTime.now().millisecondsSinceEpoch - lastSwitchTime < Durations.medium.inMilliseconds) { + if (DateTime.now().millisecondsSinceEpoch - lastSwitchTime < + Durations.medium.inMilliseconds) { return; } lastSwitchTime = DateTime.now().millisecondsSinceEpoch; @@ -34,7 +35,8 @@ class _LightDarkToggleSwitchState extends State { // Use a stateful builder so we can rebuild ourselves on click without going to a StatefulWidget return Row( children: [ - StyledImageIcon(StyledIcons.lightMode, size: iconSize, color: Colors.white), + StyledImageIcon(StyledIcons.lightMode, + size: iconSize, color: Colors.white), HSpace(Insets.sm), Stack(children: [ StyledContainer( @@ -50,7 +52,9 @@ class _LightDarkToggleSwitchState extends State { theme.surface, duration: Durations.medium, margin: EdgeInsets.only( - top: 2, left: 2 + (innerWidth - 20 - 4) * (value as double? ?? 1), right: 2), + top: 2, + left: 2 + (innerWidth - 20 - 4) * (value as double? ?? 1), + right: 2), borderRadius: BorderRadius.circular(99), width: 20, height: 20, @@ -58,7 +62,8 @@ class _LightDarkToggleSwitchState extends State { ), ]), HSpace(Insets.sm), - StyledImageIcon(StyledIcons.darkMode, size: iconSize - 2, color: ColorUtils.shiftHsl(theme.accent1, -.1)), + StyledImageIcon(StyledIcons.darkMode, + size: iconSize - 2, color: ColorUtils.shiftHsl(theme.accent1, -.1)), ], ).clickable(() => _handleTogglePressed(context), opaque: true); } diff --git a/flokk_src/lib/views/main_scaffold/main_scaffold.dart b/flokk_src/lib/views/main_scaffold/main_scaffold.dart index 2270214..a693841 100644 --- a/flokk_src/lib/views/main_scaffold/main_scaffold.dart +++ b/flokk_src/lib/views/main_scaffold/main_scaffold.dart @@ -37,12 +37,14 @@ class MainScaffoldState extends State { PageType.ContactsList, ]; - SimpleValueNotifier> checkedContactsNotifier = SimpleValueNotifier([]); + SimpleValueNotifier> checkedContactsNotifier = + SimpleValueNotifier([]); late AppModel appModel; /// Easily lookup the current state of the SidePanel - ContactPanelState? get contactsPanel => MainScaffold.sidePanelKey.currentState; + ContactPanelState? get contactsPanel => + MainScaffold.sidePanelKey.currentState; SearchBarState? get searchBar => MainScaffold.searchBarKey.currentState; @@ -68,7 +70,8 @@ class MainScaffoldState extends State { appModel.selectedContact = ContactData(); } - void editSelectedContact(String section) => contactsPanel?.showEditView(section); + void editSelectedContact(String section) => + contactsPanel?.showEditView(section); //TODO: This should be a command /// Attempt to change current page, this might not complete if user is currently editing @@ -101,11 +104,14 @@ class MainScaffoldState extends State { } /// Change selected contact, this might not complete if user is currently editing - Future trySetSelectedContact(ContactData value, {showSocial = false}) async { + Future trySetSelectedContact(ContactData value, + {showSocial = false}) async { if (!await showDiscardWarningIfNecessary()) return; //De-select? bool hasSocialChanged = showSocial != appModel.showSocialTabOnInfoView; - if (!hasSocialChanged && appModel.selectedContact != ContactData() && appModel.selectedContact.id == value.id) { + if (!hasSocialChanged && + appModel.selectedContact != ContactData() && + appModel.selectedContact.id == value.id) { value = ContactData(); } appModel.selectedContact = value; @@ -159,5 +165,4 @@ class MainScaffoldState extends State { value: this, child: MainScaffoldView(this), ); - } diff --git a/flokk_src/lib/views/main_scaffold/main_scaffold_view.dart b/flokk_src/lib/views/main_scaffold/main_scaffold_view.dart index d379623..a86b93e 100644 --- a/flokk_src/lib/views/main_scaffold/main_scaffold_view.dart +++ b/flokk_src/lib/views/main_scaffold/main_scaffold_view.dart @@ -24,10 +24,12 @@ class MainScaffoldView extends WidgetView { Widget build(BuildContext context) { /// /////////////////////////////////////////////////////////// /// Bind to AppModel when selectedContact changes, and provide it to the sub-tree - ContactData selectedContact = context.select((model) => model.selectedContact); + ContactData selectedContact = + context.select((model) => model.selectedContact); /// Bind to page-change - var currentPage = context.select((value) => value.currentMainPage); + var currentPage = + context.select((value) => value.currentMainPage); /// Flutter throws an error when it's forced to close the drawer on resize, so pre-emptively close it state.closeScaffoldOnResize(); @@ -61,17 +63,26 @@ class MainScaffoldView extends WidgetView { /// Figure out what should be visible, and the size of our viewport /// 3 cases: 1) Single Column, 2) LeftMenu + Single Column, 3) LeftMenu + Dual Column /// (Dual Column means it can show both ContentArea and EditPanel at the same time) - bool showPanel = selectedContact != ContactData(); //Contact panel is always shown if a contact is selected - bool showLeftMenu = !isNarrow; //Whether main menu is shown, or hidden behind hamburger btn - bool useSingleColumn = context.widthInches < 10; //Whether detail panel fills the entire content area - bool hideContent = showPanel && useSingleColumn; //If single column + panel, we can hide the content - double leftContentOffset = showLeftMenu ? leftMenuWidth : Insets.mGutter; //Left position for the main content stack - double contentRightPos = showPanel ? detailsPanelWidth : 0; //Right position for main content stack + bool showPanel = selectedContact != + ContactData(); //Contact panel is always shown if a contact is selected + bool showLeftMenu = + !isNarrow; //Whether main menu is shown, or hidden behind hamburger btn + bool useSingleColumn = context.widthInches < + 10; //Whether detail panel fills the entire content area + bool hideContent = showPanel && + useSingleColumn; //If single column + panel, we can hide the content + double leftContentOffset = showLeftMenu + ? leftMenuWidth + : Insets.mGutter; //Left position for the main content stack + double contentRightPos = showPanel + ? detailsPanelWidth + : 0; //Right position for main content stack /// Sometimes we want to skip the layout animations, for example, when we're changing main pages , /// we want the new page to ignore the panel that is sliding out of the view. Duration animDuration = state.skipScaffoldAnims ? .01.seconds : .35.seconds; - state.skipScaffoldAnims = false; // Reset flag so we only skip animations for one build cycle + state.skipScaffoldAnims = + false; // Reset flag so we only skip animations for one build cycle if (UniversalPlatform.isWeb && !AppModel.enableAnimationsOnWeb) { animDuration = .0.seconds; } @@ -94,7 +105,8 @@ class MainScaffoldView extends WidgetView { closedHeight: topBarHeight - 5, narrowMode: !showLeftMenu, searchEngine: state.appModel.searchEngine, - onContactPressed: (c) => state.trySetSelectedContact(c, showSocial: false), + onContactPressed: (c) => + state.trySetSelectedContact(c, showSocial: false), onSearchSubmitted: state.handleSearchSubmit, ); searchBar = RepaintBoundary(child: searchBar); @@ -159,12 +171,17 @@ class MainScaffoldView extends WidgetView { /// ///////////////////////////////////////////////// /// HAMBURGER MENU BTN - IconButton(icon: Icon(Icons.menu, size: 24, color: theme.accent1), onPressed: state.openMenu) + IconButton( + icon: Icon(Icons.menu, size: 24, color: theme.accent1), + onPressed: state.openMenu) .animatedPanelX(closeX: -50, isClosed: showLeftMenu) .positioned(left: Insets.m, top: Insets.m), /// Flokk Logo, Top-Center, only shown in narrow mode - if (isNarrow) FlokkLogo(40, theme.accent1).alignment(Alignment.topCenter).padding(top: Insets.l), + if (isNarrow) + FlokkLogo(40, theme.accent1) + .alignment(Alignment.topCenter) + .padding(top: Insets.l), /// ///////////////////////////////////////////////// /// SEARCH BAR @@ -172,7 +189,12 @@ class MainScaffoldView extends WidgetView { ]) // Shared styling for the entire content area (content + search) .constrained(minWidth: 500) .opacity(hideContent ? 0 : 1, animate: true) - .positioned(left: leftContentOffset, right: contentRightPos, bottom: 0, top: 0, animate: true) + .positioned( + left: leftContentOffset, + right: contentRightPos, + bottom: 0, + top: 0, + animate: true) .animate(animDuration, Curves.easeOut), /// ///////////////////////////////////////////////// @@ -189,7 +211,12 @@ class MainScaffoldView extends WidgetView { // Rely on the animatedPanel to toggle visibility of this when it's hidden. It renders an empty Container() when closed isClosed: !showLeftMenu, ) // Styling, pin to left, fixed width - .positioned(left: 0, top: 0, width: leftMenuWidth, bottom: 0, animate: true) + .positioned( + left: 0, + top: 0, + width: leftMenuWidth, + bottom: 0, + animate: true) .animate(animDuration, Curves.easeOut), /// ///////////////////////////////////////////////// @@ -203,7 +230,8 @@ class MainScaffoldView extends WidgetView { closeX: detailsPanelWidth, isClosed: !showPanel, ) // Styling: Pin to right, using a fixed-width for the panel - .positioned(right: 0, width: detailsPanelWidth, top: 0, bottom: 0) + .positioned( + right: 0, width: detailsPanelWidth, top: 0, bottom: 0) //.animate(animDuration, Curves.easeOut) /// Single-column mode: the edit panel is the entire width, minus the left-menu diff --git a/flokk_src/lib/views/main_scaffold/main_side_menu.dart b/flokk_src/lib/views/main_scaffold/main_side_menu.dart index b97c2a6..a5167f2 100644 --- a/flokk_src/lib/views/main_scaffold/main_side_menu.dart +++ b/flokk_src/lib/views/main_scaffold/main_side_menu.dart @@ -28,14 +28,18 @@ class MainSideMenu extends StatefulWidget { final VoidCallback? onAddNewPressed; final bool skinnyMode; - const MainSideMenu({Key? key, this.onPageSelected, this.onAddNewPressed, this.skinnyMode = false}) : super(key: key); + const MainSideMenu( + {Key? key, + this.onPageSelected, + this.onAddNewPressed, + this.skinnyMode = false}) + : super(key: key); @override _MainSideMenuState createState() => _MainSideMenuState(); } class _MainSideMenuState extends State { - Map _menuBtnOffsetsByType = {}; PageType? _prevPage; @@ -56,14 +60,17 @@ class _MainSideMenuState extends State { super.initState(); } - void _handleLogoutPressed() => LogoutCommand(context).execute(doConfirm: true); + void _handleLogoutPressed() => + LogoutCommand(context).execute(doConfirm: true); - void _handlePageSelected(PageType pageType) => widget.onPageSelected?.call(pageType); + void _handlePageSelected(PageType pageType) => + widget.onPageSelected?.call(pageType); void _updateIndicatorState(PageType type) { if (_menuBtnOffsetsByType.containsKey(type)) { Offset o = _menuBtnOffsetsByType[type] ?? Offset.zero; - setState(() => _indicatorY = o.dy - _headerHeight + _btnHeight * .5 - _indicatorHeight * .5); + setState(() => _indicatorY = + o.dy - _headerHeight + _btnHeight * .5 - _indicatorHeight * .5); } } @@ -71,13 +78,17 @@ class _MainSideMenuState extends State { Widget build(BuildContext context) { AppTheme theme = context.watch(); String versionNum = context.select((m) => m.version); + /// Bind to AppModel when currentPage changes - var currentPage = context.select((value) => value.currentMainPage); + var currentPage = + context.select((value) => value.currentMainPage); if (currentPage != _prevPage) { _updateIndicatorState(currentPage); } _prevPage = currentPage; - Color bgColor = theme.isDark? ColorUtils.blend(theme.bg1, theme.accent1, .08) : theme.accent1; + Color bgColor = theme.isDark + ? ColorUtils.blend(theme.bg1, theme.accent1, .08) + : theme.accent1; return FocusTraversalGroup( child: Container( child: Column( @@ -88,7 +99,8 @@ class _MainSideMenuState extends State { children: [ // Background layer, scaled a bit on the Y axis so it under-hangs the menu below // This opaque background is only needed when the menu is in the slide-out drawer state - StyledContainer(theme.bg1).transform(transform: Matrix4.diagonal3Values(1.0, 1.2, 1.0)), + StyledContainer(theme.bg1).transform( + transform: Matrix4.diagonal3Values(1.0, 1.2, 1.0)), /// //////////////////////////////////////////////// /// Main Flock Logo @@ -102,78 +114,88 @@ class _MainSideMenuState extends State { Stack( children: [ /// Menu-Background - StyledContainer(bgColor, borderRadius: BorderRadius.only(topRight: Corners.s10Radius)), + StyledContainer(bgColor, + borderRadius: + BorderRadius.only(topRight: Corners.s10Radius)), /// Version - Text("v$versionNum", style: TextStyles.Caption.textColor(Colors.white)).positioned(left: 4, bottom: 4), + Text("v$versionNum", + style: TextStyles.Caption.textColor(Colors.white)) + .positioned(left: 4, bottom: 4), /// //////////////////////////////////////////////////////// /// Buttons NotificationListener( - // Listen for [MainMenuOffsetNotification], dispatched from each [MainMenuBtn] that is assigned a pageType. - // We use these to position the animated indicator in [_updateIndicatorState] - onNotification: (n) { - _menuBtnOffsetsByType[n.pageType] = n.offset; - return true; // Return true so the notification stops here - }, - child: Column( - children: [ - VSpace(Insets.l), - - /// New Contact Btn - MainMenuBtn(StyledIcons.add, "Create Contact", - compact: widget.skinnyMode, - height: _btnHeight, - transparent: false, - iconSize: 20, - isSelected: true, - dottedBorder: true, - onPressed: widget.onAddNewPressed), - - VSpace(Insets.l), - - /// Dashboard Btn - MainMenuBtn( - StyledIcons.dashboard, - "DASHBOARD", - compact: widget.skinnyMode, - pageType: PageType.Dashboard, - height: _btnHeight, - isSelected: currentPage == PageType.Dashboard, - onPressed: () => _handlePageSelected(PageType.Dashboard), - ), - - /// Contacts Out Btn - MainMenuBtn( - StyledIcons.user, - "CONTACTS", - compact: widget.skinnyMode, - pageType: PageType.ContactsList, - height: _btnHeight, - isSelected: currentPage == PageType.ContactsList, - onPressed: () => _handlePageSelected(PageType.ContactsList), - ), - - Spacer(), - - /// Light / Dark Toggle - //Use a row to easily center the Toggle inside the column - [ - LightDarkToggleSwitch(), - ].toRow(mainAxisAlignment: MainAxisAlignment.center), - - VSpace(Insets.m), - - /// Sign Out Btn - TransparentBtn( - hoverColor: theme.txt.withOpacity(.05), - contentPadding: EdgeInsets.all(Insets.m), - child: Text("SIGN OUT", style: TextStyles.Btn.textColor(Colors.white)), - onPressed: _handleLogoutPressed, - ), - - ], - )).padding(all: Insets.l, bottom: Insets.m).constrained(maxWidth: 280), + // Listen for [MainMenuOffsetNotification], dispatched from each [MainMenuBtn] that is assigned a pageType. + // We use these to position the animated indicator in [_updateIndicatorState] + onNotification: (n) { + _menuBtnOffsetsByType[n.pageType] = n.offset; + return true; // Return true so the notification stops here + }, + child: Column( + children: [ + VSpace(Insets.l), + + /// New Contact Btn + MainMenuBtn(StyledIcons.add, "Create Contact", + compact: widget.skinnyMode, + height: _btnHeight, + transparent: false, + iconSize: 20, + isSelected: true, + dottedBorder: true, + onPressed: widget.onAddNewPressed), + + VSpace(Insets.l), + + /// Dashboard Btn + MainMenuBtn( + StyledIcons.dashboard, + "DASHBOARD", + compact: widget.skinnyMode, + pageType: PageType.Dashboard, + height: _btnHeight, + isSelected: currentPage == PageType.Dashboard, + onPressed: () => + _handlePageSelected(PageType.Dashboard), + ), + + /// Contacts Out Btn + MainMenuBtn( + StyledIcons.user, + "CONTACTS", + compact: widget.skinnyMode, + pageType: PageType.ContactsList, + height: _btnHeight, + isSelected: currentPage == PageType.ContactsList, + onPressed: () => + _handlePageSelected(PageType.ContactsList), + ), + + Spacer(), + + /// Light / Dark Toggle + //Use a row to easily center the Toggle inside the column + [ + LightDarkToggleSwitch(), + ].toRow( + mainAxisAlignment: MainAxisAlignment.center), + + VSpace(Insets.m), + + /// Sign Out Btn + TransparentBtn( + hoverColor: theme.txt.withOpacity(.05), + contentPadding: EdgeInsets.all(Insets.m), + child: Text("SIGN OUT", + style: + TextStyles.Btn.textColor(Colors.white)), + onPressed: _handleLogoutPressed, + ), + ], + )) + .padding(all: Insets.l, bottom: Insets.m) + .constrained(maxWidth: 280), /// Animated line that moves up and down to select the current page _AnimatedMenuIndicator(_indicatorY, height: _indicatorHeight) diff --git a/flokk_src/lib/views/main_scaffold/main_side_menu_btn.dart b/flokk_src/lib/views/main_scaffold/main_side_menu_btn.dart index 6e442ef..ca8578a 100644 --- a/flokk_src/lib/views/main_scaffold/main_side_menu_btn.dart +++ b/flokk_src/lib/views/main_scaffold/main_side_menu_btn.dart @@ -29,7 +29,8 @@ class MainMenuBtn extends StatefulWidget { this.compact = false, this.transparent = true, this.height = 60, - this.pageType = PageType.None, this.dottedBorder = false}) + this.pageType = PageType.None, + this.dottedBorder = false}) : assert((icon is AssetImage) || (icon is IconData)), super(key: key); @@ -51,32 +52,39 @@ class MainMenuBtnState extends State { /// Create the Icon / Text Row that animates opacity when selected and hides text when compactMode = true TextStyle btnStyle = TextStyles.Btn; Widget btnContents = Row( - mainAxisAlignment: widget.compact ? MainAxisAlignment.center : MainAxisAlignment.start, + mainAxisAlignment: + widget.compact ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ if (!widget.compact) HSpace(Insets.l), Padding( padding: EdgeInsets.all(2.0), - child: StyledImageIcon(widget.icon, size: widget.iconSize - 4.0, color: Colors.white), + child: StyledImageIcon(widget.icon, + size: widget.iconSize - 4.0, color: Colors.white), ), - if (!widget.compact)... { + if (!widget.compact) ...{ HSpace(Insets.l * .5), OneLineText(widget.label.toUpperCase(), style: btnStyle).flexible() } ], - ).height(widget.height).opacity(widget.isSelected ? 1 : .8, animate: true).animate(.3.seconds, Curves.easeOut); - + ) + .height(widget.height) + .opacity(widget.isSelected ? 1 : .8, animate: true) + .animate(.3.seconds, Curves.easeOut); //Wrap btn in a border... maybe - btnContents = widget.dottedBorder? DottedBorder( - dashPattern: [3, 5], - color: Colors.white.withOpacity(.7), - borderType: widget.compact? BorderType.Circle : BorderType.RRect, - radius: Corners.s8Radius, - child: Center(child: btnContents)) : btnContents; + btnContents = widget.dottedBorder + ? DottedBorder( + dashPattern: [3, 5], + color: Colors.white.withOpacity(.7), + borderType: widget.compact ? BorderType.Circle : BorderType.RRect, + radius: Corners.s8Radius, + child: Center(child: btnContents)) + : btnContents; /// Wrap contents in a btn return RawMaterialButton( - textStyle: (widget.isSelected ? TextStyles.BtnSelected : TextStyles.Btn).textColor(Colors.white), + textStyle: (widget.isSelected ? TextStyles.BtnSelected : TextStyles.Btn) + .textColor(Colors.white), fillColor: Colors.transparent, highlightColor: Colors.white.withOpacity(.1), focusElevation: 0, @@ -84,9 +92,10 @@ class MainMenuBtnState extends State { highlightElevation: 0, elevation: 0, padding: EdgeInsets.zero, - shape: widget.compact ? CircleBorder() : RoundedRectangleBorder(borderRadius: Corners.s8Border), + shape: widget.compact + ? CircleBorder() + : RoundedRectangleBorder(borderRadius: Corners.s8Border), onPressed: widget.onPressed, child: btnContents); - } } diff --git a/flokk_src/lib/views/search/search_bar.dart b/flokk_src/lib/views/search/search_bar.dart index 06e2482..ce39dc4 100644 --- a/flokk_src/lib/views/search/search_bar.dart +++ b/flokk_src/lib/views/search/search_bar.dart @@ -98,8 +98,7 @@ class SearchBarState extends State { void handleContactPressed(ContactData c) async { MainScaffoldState scaffold = context.read(); - if (!await scaffold.showDiscardWarningIfNecessary()) - return; + if (!await scaffold.showDiscardWarningIfNecessary()) return; tmpSearch.addFilterContact(c.nameFull); clearQueryString(); handleSearchSubmitted(); @@ -116,10 +115,13 @@ class SearchBarState extends State { if (evt is RawKeyDownEvent) { if (evt.logicalKey == LogicalKeyboardKey.keyK && evt.isControlPressed) { isOpen = true; - } else if (textFocusNode.hasFocus && evt.logicalKey == LogicalKeyboardKey.enter) { + } else if (textFocusNode.hasFocus && + evt.logicalKey == LogicalKeyboardKey.enter) { handleSearchSubmitted(); - } else if (textFocusNode.hasFocus && evt.logicalKey == LogicalKeyboardKey.backspace) { - if (textKey.currentState != null && (textKey.currentState?.text.isEmpty ?? true)) { + } else if (textFocusNode.hasFocus && + evt.logicalKey == LogicalKeyboardKey.backspace) { + if (textKey.currentState != null && + (textKey.currentState?.text.isEmpty ?? true)) { final tl = tmpSearch.tagList; final cl = tmpSearch.filterContactList; if (cl.isNotEmpty) { @@ -171,5 +173,4 @@ class SearchBarState extends State { @override Widget build(BuildContext context) => SearchBarView(this); - } diff --git a/flokk_src/lib/views/search/search_bar_view.dart b/flokk_src/lib/views/search/search_bar_view.dart index 525a7ea..345b1f5 100644 --- a/flokk_src/lib/views/search/search_bar_view.dart +++ b/flokk_src/lib/views/search/search_bar_view.dart @@ -36,7 +36,9 @@ class SearchBarView extends WidgetView { // Fixed content height plus top and bottom padding double barHeight = 30 + Insets.m * 1.25 * 2.0; double topPadding = state.widget.narrowMode ? Insets.m : Insets.l; - double leftPadding = state.widget.narrowMode ? 50 : 0; // Move over to not overlay with main-app menu btn + double leftPadding = state.widget.narrowMode + ? 50 + : 0; // Move over to not overlay with main-app menu btn /// CONTENT UNDERLAY Widget underlay = ContentUnderlay( isActive: isOpen && state.resultsHeight > 0, @@ -67,7 +69,10 @@ class SearchBarView extends WidgetView { .expanded() ], ), - ).padding(left: Insets.lGutter + leftPadding, right: Insets.lGutter, vertical: topPadding), + ).padding( + left: Insets.lGutter + leftPadding, + right: Insets.lGutter, + vertical: topPadding), /// Animated Search Underline if (state.resultsHeight > 0) ...{ @@ -89,7 +94,8 @@ class _AnimatedSearchCard extends StatelessWidget { final Widget? child; final SearchBarState searchBar; - const _AnimatedSearchCard(this.searchBar, {Key? key, this.child}) : super(key: key); + const _AnimatedSearchCard(this.searchBar, {Key? key, this.child}) + : super(key: key); bool get isOpen => searchBar.isOpen; @@ -98,8 +104,10 @@ class _AnimatedSearchCard extends StatelessWidget { @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - double openHeight = min(searchBar.widget.closedHeight + searchBar.resultsHeight + 1, 600); - return StyledContainer(isOpen || hasQuery ? theme.surface : theme.surface.withOpacity(.4), + double openHeight = + min(searchBar.widget.closedHeight + searchBar.resultsHeight + 1, 600); + return StyledContainer( + isOpen || hasQuery ? theme.surface : theme.surface.withOpacity(.4), height: isOpen ? openHeight : searchBar.widget.closedHeight, borderRadius: BorderRadius.circular(6), duration: Durations.fast, diff --git a/flokk_src/lib/views/search/search_engine.dart b/flokk_src/lib/views/search/search_engine.dart index 9b4bb4f..cc00098 100644 --- a/flokk_src/lib/views/search/search_engine.dart +++ b/flokk_src/lib/views/search/search_engine.dart @@ -9,7 +9,8 @@ class SearchEngine extends SimpleNotifier { List _cachedResults = []; List _tagCache = []; - get hasQuery => query.isNotEmpty || tags.isNotEmpty || filterContacts.isNotEmpty; + get hasQuery => + query.isNotEmpty || tags.isNotEmpty || filterContacts.isNotEmpty; SearchEngine copy() => SearchEngine()..copyFrom(this); @@ -38,7 +39,8 @@ class SearchEngine extends SimpleNotifier { set tags(String tags) => setAndMarkDirty(() => _tags = tags); - List get tagList => tags.split(",").where((e) => e.isNotEmpty).toList(); + List get tagList => + tags.split(",").where((e) => e.isNotEmpty).toList(); void addTag(String tag) { final tl = tagList; @@ -64,9 +66,11 @@ class SearchEngine extends SimpleNotifier { /// Filter contacts String get filterContacts => _filterContacts; - set filterContacts(String filterContacts) => setAndMarkDirty(() => _filterContacts = filterContacts); + set filterContacts(String filterContacts) => + setAndMarkDirty(() => _filterContacts = filterContacts); - List get filterContactList => filterContacts.split(",").where((e) => e.isNotEmpty).toList(); + List get filterContactList => + filterContacts.split(",").where((e) => e.isNotEmpty).toList(); void addFilterContact(String filterContact) { final fcl = filterContactList; @@ -91,7 +95,8 @@ class SearchEngine extends SimpleNotifier { /// ORDER BY ContactOrderBy get orderBy => _orderBy; - set orderBy(ContactOrderBy orderBy) => setAndMarkDirty(() => _orderBy = orderBy); + set orderBy(ContactOrderBy orderBy) => + setAndMarkDirty(() => _orderBy = orderBy); ContactOrderBy _orderBy = ContactOrderBy.FirstName; /// //////////////////////////////////////////// @@ -105,18 +110,20 @@ class SearchEngine extends SimpleNotifier { /// DATA SOURCE List get contactsList => _contactsList; - set contactsList(List value) => setAndMarkDirty(() => _contactsList = value); + set contactsList(List value) => + setAndMarkDirty(() => _contactsList = value); List _contactsList = []; List get groupsList => _groupsList; - set groupsList(List value) => setAndMarkDirty(() => _groupsList = value); + set groupsList(List value) => + setAndMarkDirty(() => _groupsList = value); List _groupsList = []; List getResults( - [List? newContacts, ContactOrderBy _orderBy = ContactOrderBy.FirstName]) { - if (newContacts != null) - contactsList = newContacts; + [List? newContacts, + ContactOrderBy _orderBy = ContactOrderBy.FirstName]) { + if (newContacts != null) contactsList = newContacts; orderBy = _orderBy; // If we have no data if (_contactsList.isEmpty) return []; @@ -141,7 +148,8 @@ class SearchEngine extends SimpleNotifier { List results = List.from(_contactsList); List groups = _buildGroups(); { - final lowerQuery = !StringUtils.isEmpty(_query) ? _query.toLowerCase() : ""; + final lowerQuery = + !StringUtils.isEmpty(_query) ? _query.toLowerCase() : ""; if (hasQuery) { results.retainWhere((c) { bool matchsGroups = false; @@ -161,7 +169,8 @@ class SearchEngine extends SimpleNotifier { bool queryNotEmpty = lowerQuery.isNotEmpty; //bool hasTags = tagList.isNotEmpty || filterContactList.isNotEmpty; bool matchsTags = matchsGroups || matchsContact; - return (queryNotEmpty && c.searchable.contains(lowerQuery)) || matchsTags; + return (queryNotEmpty && c.searchable.contains(lowerQuery)) || + matchsTags; }); } groups.retainWhere((g) { @@ -169,9 +178,11 @@ class SearchEngine extends SimpleNotifier { }); } if (orderBy == ContactOrderBy.FirstName) { - results.sort((a, b) => _nullSafeSort(a.nameGiven, b.nameGiven, _orderDesc)); + results.sort( + (a, b) => _nullSafeSort(a.nameGiven, b.nameGiven, _orderDesc)); } else if (orderBy == ContactOrderBy.LastName) { - results.sort((a, b) => _nullSafeSort(a.nameFamily, b.nameFamily, _orderDesc)); + results.sort( + (a, b) => _nullSafeSort(a.nameFamily, b.nameFamily, _orderDesc)); } _cachedResults = results; _tagCache = groups; diff --git a/flokk_src/lib/views/search/search_query_results.dart b/flokk_src/lib/views/search/search_query_results.dart index f31877c..5249538 100644 --- a/flokk_src/lib/views/search/search_query_results.dart +++ b/flokk_src/lib/views/search/search_query_results.dart @@ -34,20 +34,27 @@ class SearchResults extends StatelessWidget { listenable: state.tmpSearch, builder: (_, __) { //Add a callback hook, so the column can pass us it's size after layout. - BuildUtils.getFutureSizeFromGlobalKey(state.resultsColumnKey, (size) => state.resultsHeight = size.height); + BuildUtils.getFutureSizeFromGlobalKey(state.resultsColumnKey, + (size) => state.resultsHeight = size.height); int maxResults = 6; - int colCount = max(1, (constraints.maxWidth / 280).floor()).clamp(1, maxResults); + int colCount = max(1, (constraints.maxWidth / 280).floor()) + .clamp(1, maxResults); /// Create Result Items - List contacts = state.tmpSearch.hasQuery ? state.tmpSearch.getResults() : []; + List contacts = state.tmpSearch.hasQuery + ? state.tmpSearch.getResults() + : []; List tags = state.tmpSearch.getTagResults(); final List labelPills = tags .take(maxResults) .map((tag) => StyledLabelPill(tag.toUpperCase(), - textStyle: TextStyles.Footnote.textColor(theme.grey).letterSpace(0).textHeight(1.63), - borderRadius: Corners.s5, onPressed: () => state.handleTagPressed(tag))) + textStyle: TextStyles.Footnote.textColor(theme.grey) + .letterSpace(0) + .textHeight(1.63), + borderRadius: Corners.s5, + onPressed: () => state.handleTagPressed(tag))) .toList(); final List<_ContactSearchListItem> contactListItems = contacts @@ -76,6 +83,7 @@ class SearchResults extends StatelessWidget { ), ), }, + /// Contacts / People if (contacts.isNotEmpty) ...{ _SearchCategory( @@ -90,6 +98,7 @@ class SearchResults extends StatelessWidget { ), ), }, + /// Submit Btn if (contacts.length > 6) ...{ TransparentTextBtn( @@ -97,7 +106,10 @@ class SearchResults extends StatelessWidget { bgColor: theme.surface, bigMode: true, onPressed: state.handleSearchSubmitted, - ).constrained(width: 220, height: 60).center().padding(top: Insets.l), + ) + .constrained(width: 220, height: 60) + .center() + .padding(top: Insets.l), VSpace(Insets.m * 1.5), }, ], @@ -141,13 +153,17 @@ class _SearchCategory extends StatelessWidget { final String text; final Widget child; - _SearchCategory({required this.icon, required this.text, required this.child}); + _SearchCategory( + {required this.icon, required this.text, required this.child}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [_SearchHeading(icon, text), child.padding(horizontal: Insets.xl, top: Insets.m)], + children: [ + _SearchHeading(icon, text), + child.padding(horizontal: Insets.xl, top: Insets.m) + ], ).padding(horizontal: Insets.xl, top: Insets.l * 0.9); } } @@ -161,7 +177,10 @@ class _SearchHeading extends StatelessWidget { @override Widget build(BuildContext context) { AppTheme theme = context.watch(); - TextStyle txtStyle = TextStyles.T1.size(FontSizes.s16).letterSpace(0.8).textColor(theme.accent1Darker); + TextStyle txtStyle = TextStyles.T1 + .size(FontSizes.s16) + .letterSpace(0.8) + .textColor(theme.accent1Darker); return Row(children: [ StyledImageIcon(icon, color: theme.grey), HSpace(Insets.m * 1.5), diff --git a/flokk_src/lib/views/search/search_query_row.dart b/flokk_src/lib/views/search/search_query_row.dart index a8457d5..8d526a2 100644 --- a/flokk_src/lib/views/search/search_query_row.dart +++ b/flokk_src/lib/views/search/search_query_row.dart @@ -25,7 +25,10 @@ class SearchQueryRow extends StatelessWidget { //Calculate all padding in the row (searchIcon + padding + closeIcon + padding) double tagPadding = 30 + Insets.m + 24 + Insets.m; //Return size of text + padding - return StringUtils.measure(tag.toUpperCase(), TextStyles.Footnote.letterSpace(0)).width + tagPadding; + return StringUtils.measure( + tag.toUpperCase(), TextStyles.Footnote.letterSpace(0)) + .width + + tagPadding; } @override @@ -40,14 +43,17 @@ class SearchQueryRow extends StatelessWidget { // Calculate the width of the text input based off of the width of the search bar double contentWidth = constraints.maxWidth - Insets.l + Insets.m; // Remove size of the close and search icons (in mobile mode, they are combined) - double barQueryWidth = max(0, contentWidth - (Sizes.iconMed + Insets.l)); + double barQueryWidth = + max(0, contentWidth - (Sizes.iconMed + Insets.l)); if (state.widget.narrowMode == false) { barQueryWidth -= (Sizes.iconMed + Insets.m * 1.5); } //Subtract widths of tags and contacts, to get the max size for text input double barTextFieldWidth = barQueryWidth; - state.tmpSearch.tagList.forEach((t) => barTextFieldWidth -= calcTagWidth(t)); - state.tmpSearch.filterContactList.forEach((fc) => barTextFieldWidth -= calcTagWidth(fc)); + state.tmpSearch.tagList + .forEach((t) => barTextFieldWidth -= calcTagWidth(t)); + state.tmpSearch.filterContactList + .forEach((fc) => barTextFieldWidth -= calcTagWidth(fc)); //Enforce min-size of 200px for search input barTextFieldWidth = max(200, barTextFieldWidth); @@ -67,21 +73,29 @@ class SearchQueryRow extends StatelessWidget { children: [ for (var tag in state.tmpSearch.tagList) ...{ StyledGroupLabel( - icon: StyledIcons.label, - text: tag, - onClose: () => state.handleRemoveTag(tag)).padding(right: Insets.m), + icon: StyledIcons.label, + text: tag, + onClose: () => state.handleRemoveTag(tag)) + .padding(right: Insets.m), }, - for (var filterContact in state.tmpSearch.filterContactList) ...{ + for (var filterContact + in state.tmpSearch.filterContactList) ...{ StyledGroupLabel( icon: StyledIcons.user, text: filterContact, - onClose: () => state.handleRemoveFilterContact(filterContact)).padding(right: Insets.m), + onClose: () => state.handleRemoveFilterContact( + filterContact)).padding(right: Insets.m), }, Container( - constraints: BoxConstraints(maxWidth: barTextFieldWidth), + constraints: + BoxConstraints(maxWidth: barTextFieldWidth), child: StyledSearchTextInput( - contentPadding: EdgeInsets.all(Insets.m * 1.25 - 0.5).copyWith(left: 0), - hintText: state.widget.narrowMode ? "" : "Search for contacts", + contentPadding: + EdgeInsets.all(Insets.m * 1.25 - 0.5) + .copyWith(left: 0), + hintText: state.widget.narrowMode + ? "" + : "Search for contacts", key: state.textKey, onChanged: state.handleSearchChanged, // Disabled because this callback has different behavior on web for some reason, diff --git a/flokk_src/lib/views/welcome/animated_bird_splash.dart b/flokk_src/lib/views/welcome/animated_bird_splash.dart index 2c8ea86..02fae3a 100644 --- a/flokk_src/lib/views/welcome/animated_bird_splash.dart +++ b/flokk_src/lib/views/welcome/animated_bird_splash.dart @@ -12,14 +12,18 @@ class AnimatedBirdSplashWidget extends StatefulWidget { final bool showLogo; const AnimatedBirdSplashWidget( - {Key? key, this.alignment = Alignment.center, this.showText = false, this.showLogo = true}) + {Key? key, + this.alignment = Alignment.center, + this.showText = false, + this.showLogo = true}) : super(key: key); @override _AnimatedBirdSplashState createState() => _AnimatedBirdSplashState(); } -class _AnimatedBirdSplashState extends State with SingleTickerProviderStateMixin { +class _AnimatedBirdSplashState extends State + with SingleTickerProviderStateMixin { late GooeyEdge _gooeyEdge; late AnimationController _animationController; @@ -29,7 +33,8 @@ class _AnimatedBirdSplashState extends State with Sing void initState() { _gooeyEdge = GooeyEdge(); _animationController = AnimationController(vsync: this); - _animationController.repeat(reverse: true, min: 0.0, max: 1.0, period: 800.milliseconds); + _animationController.repeat( + reverse: true, min: 0.0, max: 1.0, period: 800.milliseconds); _animationController.addListener(_tick); super.initState(); } @@ -41,7 +46,8 @@ class _AnimatedBirdSplashState extends State with Sing } void _tick() { - _gooeyEdge.tick(_animationController.lastElapsedDuration ?? Duration(milliseconds: 0)); + _gooeyEdge.tick( + _animationController.lastElapsedDuration ?? Duration(milliseconds: 0)); _cloudXOffset += _animationController.velocity * 0.08; while (_cloudXOffset > 800.0) { _cloudXOffset -= 800.0; @@ -63,7 +69,8 @@ class _AnimatedBirdSplashState extends State with Sing clipper: AnimatedBirdSplashClipper(_gooeyEdge), child: Stack(children: [ /// BG - _BuildImage(bgImagePath, BoxFit.fill).positioned(left: 0, top: 0, right: 0, bottom: 0), + _BuildImage(bgImagePath, BoxFit.fill) + .positioned(left: 0, top: 0, right: 0, bottom: 0), /// CLOUD 1 _BuildImage(cloudImagePath) @@ -87,7 +94,9 @@ class _AnimatedBirdSplashState extends State with Sing textAlign: TextAlign.center, ) //Bottom positioned, fades in and out .alignment(Alignment.bottomCenter) - .translate(offset: Offset(0, 46)) // Offset text below the bottom edge of the images + .translate( + offset: Offset( + 0, 46)) // Offset text below the bottom edge of the images .opacity(widget.showText ? 1 : 0, animate: true) .animate(Durations.slow, Curves.easeOut) .positioned(left: 0, top: 0, right: 0, bottom: 0) diff --git a/flokk_src/lib/views/welcome/animated_bird_splash_clipper.dart b/flokk_src/lib/views/welcome/animated_bird_splash_clipper.dart index 7dcc9c1..665fd7a 100644 --- a/flokk_src/lib/views/welcome/animated_bird_splash_clipper.dart +++ b/flokk_src/lib/views/welcome/animated_bird_splash_clipper.dart @@ -19,9 +19,7 @@ class AnimatedBirdSplashClipper extends CustomClipper { } } - class GooeyEdge { - static Random random = Random(4444); List<_Point> points = []; @@ -33,16 +31,18 @@ class GooeyEdge { int lastT = 0; // TODO: initValues? - GooeyEdge({this.count=8, this.edgeFactor=0.09}) { + GooeyEdge({this.count = 8, this.edgeFactor = 0.09}) { points = []; int ttl = count * 4 - 2; - for (int i=0; i WelcomePageState(); @@ -97,10 +98,14 @@ class WelcomePageState extends State { /// Load initial contacts isLoading = true; await RefreshContactsCommand(context).execute(); - await RefreshSocialCommand(context).execute(context.read().allContacts); + await RefreshSocialCommand(context) + .execute(context.read().allContacts); /// Show main app view - Navigator.push(context, PageRoutes.fade(() => MainScaffold(), Durations.slow.inMilliseconds * .001)); + Navigator.push( + context, + PageRoutes.fade( + () => MainScaffold(), Durations.slow.inMilliseconds * .001)); } void handleUrlClicked() => UrlLauncher.open(authUrl); @@ -133,7 +138,8 @@ class WelcomePageState extends State { isLoading = true; authCodeError = false; await Future.delayed(Duration(milliseconds: 500)); - ServiceResult result = await googleRest.auth.authorizeDevice(authInfo!.deviceCode); + ServiceResult result = + await googleRest.auth.authorizeDevice(authInfo!.deviceCode); GoogleAuthResults? authResults = result.content; if (authResults != null) { //We have a token! Update the model. @@ -198,7 +204,11 @@ class _WelcomePageStateView extends StatelessWidget { ), ) .opacity(1.0) - .padding(right: (state.showContent && state.twoColumnMode ? contentWidth : 0), animate: true) + .padding( + right: (state.showContent && state.twoColumnMode + ? contentWidth + : 0), + animate: true) .animate( skipBirdTransition ? 0.seconds : Durations.slow, Curves.easeOut, @@ -213,7 +223,11 @@ class _WelcomePageStateView extends StatelessWidget { duration: Durations.slow.inMilliseconds * .001, ) // Pin the left side on fullscreen, respect existing width otherwise - .positioned(top: 0, bottom: 0, right: 0, left: state.twoColumnMode ? null : 0) + .positioned( + top: 0, + bottom: 0, + right: 0, + left: state.twoColumnMode ? null : 0) ], ), ), @@ -235,7 +249,9 @@ class _WelcomeContentStack extends StatelessWidget { WelcomePageState state = context.watch(); //Bg shape is rounded on the left corners when in dual-column mode, but square in full-screen BorderRadius? getBgShape() => state.twoColumnMode - ? BorderRadius.only(topLeft: Radius.circular(Corners.s10), bottomLeft: Radius.circular(Corners.s10)) + ? BorderRadius.only( + topLeft: Radius.circular(Corners.s10), + bottomLeft: Radius.circular(Corners.s10)) : null; AppTheme theme = context.watch(); @@ -247,7 +263,9 @@ class _WelcomeContentStack extends StatelessWidget { duration: Durations.slow, index: state.pageIndex, children: [ - WelcomePageStep1(singleColumnMode: !state.twoColumnMode).scrollable().center(), + WelcomePageStep1(singleColumnMode: !state.twoColumnMode) + .scrollable() + .center(), WelcomePageStep2().scrollable().center(), ], ).padding(vertical: Insets.l * 1.5).center(), diff --git a/flokk_src/lib/views/welcome/welcome_page_step1.dart b/flokk_src/lib/views/welcome/welcome_page_step1.dart index ac3aeee..8f4984f 100644 --- a/flokk_src/lib/views/welcome/welcome_page_step1.dart +++ b/flokk_src/lib/views/welcome/welcome_page_step1.dart @@ -12,25 +12,29 @@ import 'package:provider/provider.dart'; class WelcomePageStep1 extends StatelessWidget { final bool singleColumnMode; - const WelcomePageStep1({Key? key, this.singleColumnMode = false}) : super(key: key); + const WelcomePageStep1({Key? key, this.singleColumnMode = false}) + : super(key: key); @override Widget build(BuildContext context) { WelcomePageState state = context.watch(); - TextStyle bodyTxtStyle = TextStyles.Body1.textColor(Color(0xfff1f7f0)).textHeight(1.6); + TextStyle bodyTxtStyle = + TextStyles.Body1.textColor(Color(0xfff1f7f0)).textHeight(1.6); return SeparatedColumn( separatorBuilder: () => SizedBox(height: Insets.l), mainAxisAlignment: MainAxisAlignment.start, children: [ if (singleColumnMode) FlokkLogo(50, Colors.white).center(), if (singleColumnMode) - AnimatedBirdSplashWidget(alignment: Alignment.bottomCenter, showLogo: false) + AnimatedBirdSplashWidget( + alignment: Alignment.bottomCenter, showLogo: false) .padding(all: Insets.m * 1.5) .height(context.heightPx * .4), [ Text( "Welcome to Flokk Contacts", - style: TextStyles.CalloutFocus.bold.size(24).textColor(Colors.white), + style: + TextStyles.CalloutFocus.bold.size(24).textColor(Colors.white), textAlign: TextAlign.center, ), Text( @@ -45,7 +49,8 @@ class WelcomePageStep1 extends StatelessWidget { ), ].toColumn().constrained(maxWidth: 400), kIsWeb - ? Image.asset("assets/images/google-signin.png", height: 50).gestures(onTap: state.handleStartPressed) + ? Image.asset("assets/images/google-signin.png", height: 50) + .gestures(onTap: state.handleStartPressed) : PrimaryTextBtn( "LET'S START!", bigMode: true, diff --git a/flokk_src/lib/views/welcome/welcome_page_step2.dart b/flokk_src/lib/views/welcome/welcome_page_step2.dart index 465bff4..883047a 100644 --- a/flokk_src/lib/views/welcome/welcome_page_step2.dart +++ b/flokk_src/lib/views/welcome/welcome_page_step2.dart @@ -23,16 +23,19 @@ class _WelcomePageStep2State extends State { AppTheme theme = context.watch(); WelcomePageState state = context.watch(); - TextStyle bodyTxtStyle = TextStyles.Body1.textColor(Colors.white).textHeight(1.6); + TextStyle bodyTxtStyle = + TextStyles.Body1.textColor(Colors.white).textHeight(1.6); TextStyle titleTxtStyle = TextStyles.T1.textColor(theme.accent1Darker); - TextStyle headerTxtStyle = TextStyles.CalloutFocus.bold.size(24).textColor(Colors.white); + TextStyle headerTxtStyle = + TextStyles.CalloutFocus.bold.size(24).textColor(Colors.white); return state.isLoading ? StyledProgressSpinner() : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("Authorization", style: headerTxtStyle, textAlign: TextAlign.center), + Text("Authorization", + style: headerTxtStyle, textAlign: TextAlign.center), VSpace(Insets.l * 2), /// //////////////////////////////////////////////// @@ -51,14 +54,20 @@ class _WelcomePageStep2State extends State { : Stack( fit: StackFit.expand, children: [ - SelectableText("${state.authCode}", style: bodyTxtStyle.size(16)).center(), + SelectableText("${state.authCode}", + style: bodyTxtStyle.size(16)) + .center(), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ColorShiftIconBtn(StyledIcons.refresh, - size: 28, color: Colors.white, onPressed: state.handleRefreshPressed), + size: 28, + color: Colors.white, + onPressed: state.handleRefreshPressed), ColorShiftIconBtn(StyledIcons.copy, - size: 24, color: Colors.white, onPressed: state.handleCodeClicked), + size: 24, + color: Colors.white, + onPressed: state.handleCodeClicked), ], ).padding(horizontal: Insets.m), ], @@ -82,12 +91,16 @@ class _WelcomePageStep2State extends State { : Stack( fit: StackFit.expand, children: [ - SelectableText("${state.authUrl}", style: bodyTxtStyle.size(16)).center(), + SelectableText("${state.authUrl}", + style: bodyTxtStyle.size(16)) + .center(), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ColorShiftIconBtn(StyledIcons.linkout, - size: 24, color: Colors.white, onPressed: state.handleUrlClicked), + size: 24, + color: Colors.white, + onPressed: state.handleUrlClicked), ], ).padding(horizontal: Insets.m), ], From 0330b7cd0d8822d0499801177547c6af3818023e Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Wed, 1 Sep 2021 09:09:12 -0700 Subject: [PATCH 2/2] Fix compile errors on the master/dev channels Return type has changed from bool -> KeyPressEvent Related to: https://github.com/flutter/flutter/issues/45367 --- flokk_src/lib/styled_components/styled_text_input.dart | 4 ++-- flokk_src/lib/views/search/search_bar_view.dart | 6 +++--- flokk_src/pubspec.lock | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flokk_src/lib/styled_components/styled_text_input.dart b/flokk_src/lib/styled_components/styled_text_input.dart index 887d1c6..dc948af 100644 --- a/flokk_src/lib/styled_components/styled_text_input.dart +++ b/flokk_src/lib/styled_components/styled_text_input.dart @@ -149,10 +149,10 @@ class StyledSearchTextInputState extends State { if (evt is RawKeyDownEvent) { if (evt.logicalKey == LogicalKeyboardKey.escape) { widget.onEditingCancel?.call(); - return true; + return KeyEventResult.handled; } } - return false; + return KeyEventResult.ignored; }, canRequestFocus: true, ); diff --git a/flokk_src/lib/views/search/search_bar_view.dart b/flokk_src/lib/views/search/search_bar_view.dart index 345b1f5..a462c55 100644 --- a/flokk_src/lib/views/search/search_bar_view.dart +++ b/flokk_src/lib/views/search/search_bar_view.dart @@ -19,14 +19,14 @@ class SearchBarView extends WidgetView { bool get isOpen => state.isOpen; - bool _handleKeyPress(FocusNode node, RawKeyEvent evt) { + KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent evt) { if (evt is RawKeyDownEvent) { if (evt.logicalKey == LogicalKeyboardKey.escape) { state.cancel(); - return true; + return KeyEventResult.handled; } } - return false; + return KeyEventResult.ignored; } @override diff --git a/flokk_src/pubspec.lock b/flokk_src/pubspec.lock index 76c8de2..ca679cc 100644 --- a/flokk_src/pubspec.lock +++ b/flokk_src/pubspec.lock @@ -451,7 +451,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" mime: dependency: transitive description: