Skip to content

Commit

Permalink
fix: Added UniversalContainer.
Browse files Browse the repository at this point in the history
  • Loading branch information
mathrunet committed Mar 2, 2023
1 parent 99785de commit beae523
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 15 deletions.
6 changes: 5 additions & 1 deletion packages/masamune/lib/masamune.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// Package imports:
import 'package:universal_platform/universal_platform.dart';

// Project imports:
import 'package:masamune/masamune.dart';
import 'package:universal_platform/universal_platform.dart';

export 'package:katana/katana.dart';
export 'package:katana_auth/katana_auth.dart';
Expand Down Expand Up @@ -55,9 +57,11 @@ part 'ui/grid_builder.dart';
part 'ui/list_builder.dart';
part 'ui/reorderable_list_builder.dart';

part 'universal/universal_scope.dart';
part 'universal/universal_scaffold.dart';
part 'universal/universal_app_bar.dart';
part 'universal/universal_list_view.dart';
part 'universal/universal_grid_view.dart';
part 'universal/universal_list_builder.dart';
part 'universal/universal_grid_builder.dart';
part 'universal/universal_container.dart';
35 changes: 27 additions & 8 deletions packages/masamune/lib/src/masamune_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,14 @@ class MasamuneApp extends StatelessWidget {
this.builder,
this.onBuildAppFilters,
this.masamuneAdapters = const <MasamuneAdapter>[],
this.breakpoint,
});

/// You can specify the breakpoint at which the UI will change to a mobile-oriented UI.
///
/// UIがモバイル向けのUIに変化するブレークポイントを指定できます。
final ResponsiveBreakpoint? breakpoint;

/// You can specify the plug-in adapter used by Masamune Framework.
///
/// Masamune Frameworkで用いられるプラグインアダプターを指定することができます。
Expand Down Expand Up @@ -384,21 +390,24 @@ class MasamuneApp extends StatelessWidget {
Widget build(BuildContext context) {
var child = _buildAppFunctions(
context,
_buildAppStorage(
_buildUniversal(
context,
_buildAppAuth(
_buildAppStorage(
context,
_buildAppLogger(
_buildAppAuth(
context,
_buildAppModel(
_buildAppLogger(
context,
_buildAppScoped(
_buildAppModel(
context,
_buildAppTheme(
_buildAppScoped(
context,
_buildAppLocalize(
_buildAppTheme(
context,
_buildAppRouter(context),
_buildAppLocalize(
context,
_buildAppRouter(context),
),
),
),
),
Expand All @@ -420,6 +429,16 @@ class MasamuneApp extends StatelessWidget {
return child;
}

Widget _buildUniversal(BuildContext context, Widget child) {
if (breakpoint != null) {
return UniversalScope(
breakpoint: breakpoint,
child: child,
);
}
return child;
}

Widget _buildAppModel(BuildContext context, Widget child) {
if (modelAdapter != null) {
return ModelAdapterScope(
Expand Down
199 changes: 199 additions & 0 deletions packages/masamune/lib/universal/universal_container.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
part of masamune;

/// Create a container that is responsive.
///
/// It is recommended to place it directly under [UniversalScaffold.body].
/// Otherwise, [Container] is fine.
///
/// The maximum width is automatically set according to [UniversalScaffold.breakpoint].
///
/// レスポンシブに対応したコンテナを作成します。
///
/// [UniversalScaffold.body]の直下に置くことをおすすめします。
/// それ以外は[Container]で問題ございません。
///
/// [UniversalScaffold.breakpoint]に応じて最大の横幅が自動で設定されます。
class UniversalContainer extends StatelessWidget {
/// Create a container that is responsive.
///
/// It is recommended to place it directly under [UniversalScaffold.body].
/// Otherwise, [Container] is fine.
///
/// The maximum width is automatically set according to [UniversalScaffold.breakpoint].
///
/// レスポンシブに対応したコンテナを作成します。
///
/// [UniversalScaffold.body]の直下に置くことをおすすめします。
/// それ以外は[Container]で問題ございません。
///
/// [UniversalScaffold.breakpoint]に応じて最大の横幅が自動で設定されます。
const UniversalContainer({
super.key,
this.child,
this.padding,
this.margin,
this.color,
this.decoration,
this.foregroundDecoration,
this.width,
this.height,
this.constraints,
this.alignment = Alignment.center,
this.transform,
this.transformAlignment,
this.clipBehavior = Clip.none,
this.paddingWhenNotFullWidth,
this.breakpoint,
});

/// You can specify the breakpoint at which the UI will change to a mobile-oriented UI.
///
/// UIがモバイル向けのUIに変化するブレークポイントを指定できます。
final ResponsiveBreakpoint? breakpoint;

/// [padding] when the width does not exceed [UniversalScaffold.breakpoint] and the width is fixed.If [Null], [padding] is used.
///
/// 横幅が[UniversalScaffold.breakpoint]を超えない場合、横幅が固定されているときの[padding][Null]の場合は[padding]が利用されます。
final EdgeInsetsGeometry? paddingWhenNotFullWidth;

/// This value holds the alignment to be used by the container.
///
/// この値はコンテナに使用される配置を保持します。
final AlignmentGeometry alignment;

/// Defines where to place the widget with respect to its parent.
///
/// 親要素に対してウィジェットを配置する位置を定義します。
final EdgeInsetsGeometry? padding;

/// Sets the background color of the container.
///
/// If [decoration] is specified, set the background color within [decoration].
///
/// コンテナの背景色を設定します。
///
/// [decoration]が指定されている場合は、[decoration]内で背景色を設定してください。
final Color? color;

/// Sets the container background decoration.
///
/// コンテナの背景の装飾を設定します。
final Decoration? decoration;

/// Sets the decorations to be drawn before the container's [builder].
///
/// コンテナの[builder]より前に描画される装飾を設定します。
final Decoration? foregroundDecoration;

/// Sets the width of the container.
///
/// Takes precedence over [breakpoint] and [constraints].
///
/// コンテナの横幅を設定します。
///
/// [breakpoint][constraints]より優先されます。
final double? width;

/// Sets the height of the container.
///
/// Takes precedence over [breakpoint] and [constraints].
///
/// コンテナの縦幅を設定します。
///
/// [breakpoint][constraints]より優先されます。
final double? height;

/// Sets size constraints for containers.
///
/// If [breakpoint] is set, it takes precedence.
///
/// コンテナのサイズ制約を設定します。
///
/// [breakpoint]が設定されている場合はそれが優先されます。
final BoxConstraints? constraints;

/// Sets the margin of the container.
///
/// コンテナのマージンを設定します。
final EdgeInsetsGeometry? margin;

/// The transformation matrix to apply before painting the container.
///
/// コンテナの描画前に適用する変換行列。
final Matrix4? transform;

/// The alignment of the origin, relative to the size of the container, if [transform] is specified.
///
/// When [transform] is null, the value of this property is ignored.
///
/// [transform]が指定されている場合、コンテナのサイズに対する原点の配置を設定します。
///
/// [transform]がnullの場合、このプロパティの値は無視されます。
///
/// See also:
///
/// * [Transform.alignment], which is set by this property.
final AlignmentGeometry? transformAlignment;

/// The clip behavior when [Container.decoration] is not null.
///
/// Defaults to [Clip.none]. Must be [Clip.none] if [decoration] is null.
///
/// If a clip is to be applied, the [Decoration.getClipPath] method
/// for the provided decoration must return a clip path. (This is not
/// supported by all decorations; the default implementation of that
/// method throws an [UnsupportedError].)
///
/// [Container.decoration]がnullでない場合のクリップの振る舞い。
///
/// デフォルトは[Clip.none]です。[decoration]がnullの場合は[Clip.none]である必要があります。
///
/// クリップを適用する場合、提供された装飾の[Decoration.getClipPath]メソッドはクリップパスを返す必要があります。
/// (これはすべての装飾に対応していません。そのメソッドのデフォルト実装は[UnsupportedError]をスローします。)
final Clip clipBehavior;

/// Widgets to be stored in [Container].
///
/// [Container]の中に格納するウィジェット。
final Widget? child;

@override
Widget build(BuildContext context) {
final breakpoint =
this.breakpoint ?? ResponsiveScaffold.of(context)?.breakpoint;

return Align(
alignment: alignment,
child: Container(
constraints:
constraints?.copyWith(maxWidth: breakpoint?.width(context)) ??
BoxConstraints(
maxWidth: breakpoint?.width(context) ?? double.infinity,
),
padding: _effectivePadding(context, breakpoint),
margin: margin,
color: color,
decoration: decoration,
foregroundDecoration: foregroundDecoration,
width: width,
height: height,
alignment: alignment,
transform: transform,
transformAlignment: transformAlignment,
clipBehavior: clipBehavior,
child: child,
),
);
}

EdgeInsetsGeometry? _effectivePadding(
BuildContext context,
ResponsiveBreakpoint? breakpoint,
) {
if (breakpoint?.width(context) == double.infinity) {
return padding;
} else {
return paddingWhenNotFullWidth ?? padding;
}
}
}
5 changes: 3 additions & 2 deletions packages/masamune/lib/universal/universal_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ class _UniversalScaffoldState extends State<UniversalScaffold> {

@override
Widget build(BuildContext context) {
final universalScope = UniversalScope.of(context);
final appBar = widget.appBar;
final useSliver = !(appBar == null ||
appBar is! UniversalAppBar ||
Expand All @@ -421,7 +422,7 @@ class _UniversalScaffoldState extends State<UniversalScaffold> {
if (useSliver) {
return ResponsiveScaffold(
key: widget.key,
breakpoint: widget.breakpoint,
breakpoint: universalScope?.breakpoint ?? widget.breakpoint,
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
Expand Down Expand Up @@ -455,7 +456,7 @@ class _UniversalScaffoldState extends State<UniversalScaffold> {
} else {
return ResponsiveScaffold(
key: widget.key,
breakpoint: widget.breakpoint,
breakpoint: universalScope?.breakpoint ?? widget.breakpoint,
appBar: _toMobileAppBar(context),
body: _buildBody(context, _loading(context)),
floatingActionButton: widget.floatingActionButton,
Expand Down
48 changes: 48 additions & 0 deletions packages/masamune/lib/universal/universal_scope.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
part of masamune;

/// Scope for UniversalUI configuration.
///
/// If [breakpoint] is specified, it will overwrite [breakpoint] in [UniversalScaffold].
///
/// UniversalUIの設定を行うためのスコープ。
///
/// [breakpoint]を指定すると、[UniversalScaffold][breakpoint]が上書きされます。
class UniversalScope extends InheritedWidget {
/// Scope for UniversalUI configuration.
///
/// If [breakpoint] is specified, it will overwrite [breakpoint] in [UniversalScaffold].
///
/// UniversalUIの設定を行うためのスコープ。
///
/// [breakpoint]を指定すると、[UniversalScaffold][breakpoint]が上書きされます。
const UniversalScope({
super.key,
required super.child,
this.breakpoint,
});

/// You can specify the breakpoint at which the UI will change to a mobile-oriented UI.
///
/// UIがモバイル向けのUIに変化するブレークポイントを指定できます。
final ResponsiveBreakpoint? breakpoint;

/// Get [UniversalScope] by passing [context].
///
/// If [UniversalScope] is not present, an error is output.
///
/// [context]を渡すことで、[UniversalScope]を取得します。
///
/// [UniversalScope]がない場合はエラーが出力されます。
static UniversalScope? of(BuildContext context) {
final scope =
context.getElementForInheritedWidgetOfExactType<UniversalScope>();
assert(
scope != null,
"UniversalScope is not found. Place [UniversalScope] widget closer to the root.",
);
return scope?.widget as UniversalScope?;
}

@override
bool updateShouldNotify(UniversalScope oldWidget) => false;
}
8 changes: 4 additions & 4 deletions packages/masamune/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,10 @@ packages:
dependency: "direct main"
description:
name: katana_responsive
sha256: "794cd0adc07394f3208dd521c650acefaa4a1f9c039e0e41e7400b2ee71f68f4"
sha256: "11803aa79a320f3946b8ae69dae657079e6f23449303cda8874d155bbd7ccaf3"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
katana_router:
dependency: "direct main"
description:
Expand Down Expand Up @@ -396,10 +396,10 @@ packages:
dependency: "direct main"
description:
name: katana_ui
sha256: e5eaee5c6b89ba6e87f6d242d04461e17aad8d24884632b8aa28ab80380d1e04
sha256: "092af39eca3ba0b7ea6152e80c5d5a39d064002987ec5d839eaf6f928a9eaf81"
url: "https://pub.dev"
source: hosted
version: "1.1.10"
version: "1.1.11"
lints:
dependency: transitive
description:
Expand Down

0 comments on commit beae523

Please sign in to comment.