-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add manufacturer banner (#1598)
* [WIP] Implement manufacturer banner * Hide manufacturer banner when user is logged in. * [WIP] Update manufacturer_banner theme data * [WIP] Implement ManufacturerAdvertisementContainer class, add tests * [WIP] Fix tests * Minor changes * Add copyright licenses * Add copyright licenses Co-authored-by: solid-vovabeloded <vova.beloded@solid.software> Co-authored-by: solid-maksymtielnyi <maksym.tielnyi@solid.software>
- Loading branch information
1 parent
7548703
commit cd19923
Showing
11 changed files
with
569 additions
and
9 deletions.
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
...ion/manufacturer_advertisement_container/widget/manufacturer_advertisement_container.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Use of this source code is governed by the Apache License, Version 2.0 | ||
// that can be found in the LICENSE file. | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:metrics/common/presentation/manufacturer_banner/widget/manufacturer_banner.dart'; | ||
|
||
/// A widget that displays the banner with the product manufacturer information | ||
/// in the bottom right over the child widget. | ||
class ManufacturerAdvertisementContainer extends StatelessWidget { | ||
final Widget _child; | ||
final bool _isEnabled; | ||
|
||
/// Creates a new instance of [ManufacturerAdvertisementContainer]. | ||
/// | ||
/// Throws an [AssertionError] if the given [child] parameter is `null`. | ||
/// Throws an [AssertionError] if the giver [isEnabled] parameter is `null`. | ||
const ManufacturerAdvertisementContainer({ | ||
@required Widget child, | ||
@required bool isEnabled, | ||
}) : assert(child != null), | ||
assert(isEnabled != null), | ||
_child = child, | ||
_isEnabled = isEnabled; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Stack( | ||
children: [ | ||
_child, | ||
if (_isEnabled) | ||
const Positioned( | ||
bottom: 0.0, | ||
right: 0.0, | ||
child: ManufacturerBanner(), | ||
), | ||
], | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
metrics/web/lib/common/presentation/manufacturer_banner/widget/manufacturer_banner.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Use of this source code is governed by the Apache License, Version 2.0 | ||
// that can be found in the LICENSE file. | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/rendering.dart'; | ||
import 'package:metrics/base/presentation/widgets/material_container.dart'; | ||
import 'package:metrics/base/presentation/widgets/svg_image.dart'; | ||
import 'package:metrics/common/presentation/metrics_theme/widgets/metrics_theme.dart'; | ||
import 'package:metrics/common/presentation/strings/common_strings.dart'; | ||
import 'package:url_launcher/url_launcher.dart'; | ||
|
||
/// A widget that displays the banner with the product manufacturer information. | ||
class ManufacturerBanner extends StatefulWidget { | ||
/// Creates a new instance of the [ManufacturerBanner]. | ||
const ManufacturerBanner({Key key}) : super(key: key); | ||
|
||
@override | ||
_ManufacturerBannerState createState() => _ManufacturerBannerState(); | ||
} | ||
|
||
class _ManufacturerBannerState extends State<ManufacturerBanner> | ||
with SingleTickerProviderStateMixin { | ||
/// A [Duration] of this banner folding animation. | ||
static const _animationDuration = Duration(milliseconds: 250); | ||
|
||
/// An [AnimationController] of this banner folding animation. | ||
AnimationController _controller; | ||
|
||
/// A [Timer] of this banner preview. | ||
Timer _previewTimer; | ||
|
||
@override | ||
void initState() { | ||
_controller = AnimationController( | ||
vsync: this, | ||
duration: _animationDuration, | ||
); | ||
_controller.value = 1.0; | ||
|
||
_previewTimer = Timer(const Duration(seconds: 10), _closeBanner); | ||
|
||
super.initState(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final themeData = MetricsTheme.of(context).manufacturerBannerThemeData; | ||
|
||
return GestureDetector( | ||
onTap: _openManufacturerLink, | ||
child: MouseRegion( | ||
cursor: SystemMouseCursors.click, | ||
onEnter: (_) => _openBanner(), | ||
onExit: (_) => _closeBanner(), | ||
child: AnimatedBuilder( | ||
animation: _controller, | ||
builder: (_, __) { | ||
return MaterialContainer( | ||
padding: const EdgeInsets.all(8.0), | ||
elevation: themeData.elevation, | ||
backgroundColor: themeData.backgroundColor, | ||
borderRadius: const BorderRadius.only( | ||
topLeft: Radius.circular(10.0), | ||
), | ||
child: Row( | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
const SvgImage( | ||
'icons/solid_logo.svg', | ||
), | ||
SizeTransition( | ||
sizeFactor: _controller, | ||
axis: Axis.horizontal, | ||
axisAlignment: -1.0, | ||
child: Padding( | ||
padding: const EdgeInsets.only(left: 8.0), | ||
child: Text( | ||
CommonStrings.builtBySolidSoftware, | ||
style: themeData.textStyle, | ||
), | ||
), | ||
), | ||
], | ||
), | ||
); | ||
}, | ||
), | ||
), | ||
); | ||
} | ||
|
||
/// Starts this banner opening animation. | ||
/// | ||
/// Cancels the [_previewTimer] is there any running. | ||
void _openBanner() { | ||
_cancelPreviewTimer(); | ||
_controller.stop(); | ||
_controller.forward(); | ||
} | ||
|
||
/// Starts this banner closing animation. | ||
/// | ||
/// Cancels the [_previewTimer] is there any running. | ||
void _closeBanner() { | ||
_cancelPreviewTimer(); | ||
_controller.stop(); | ||
_controller.reverse(); | ||
} | ||
|
||
/// Cancels the [_previewTimer] if it is running. | ||
/// | ||
/// If the [_previewTimer] is null does nothing. | ||
void _cancelPreviewTimer() { | ||
if (_previewTimer == null) return; | ||
|
||
_previewTimer.cancel(); | ||
_previewTimer = null; | ||
} | ||
|
||
/// Opens the manufacturer link. | ||
void _openManufacturerLink() { | ||
launch('https://solid.software/'); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_cancelPreviewTimer(); | ||
_controller.dispose(); | ||
super.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
metrics/web/lib/common/presentation/scaffold/widget/metrics_scaffold.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
...anufacturer_advertisement_container/widget/manufacturer_advertisement_container_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Use of this source code is governed by the Apache License, Version 2.0 | ||
// that can be found in the LICENSE file. | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:metrics/common/presentation/manufacturer_advertisement_container/widget/manufacturer_advertisement_container.dart'; | ||
import 'package:metrics/common/presentation/manufacturer_banner/widget/manufacturer_banner.dart'; | ||
import 'package:network_image_mock/network_image_mock.dart'; | ||
|
||
void main() { | ||
group("ManufacturerAdvertisementContainer", () { | ||
final Key childKey = GlobalKey(); | ||
final Widget child = Text('Child widget', key: childKey); | ||
|
||
testWidgets( | ||
"throws an AssertionError if the isEnabled parameter is null", | ||
(tester) async { | ||
expect( | ||
() => ManufacturerAdvertisementContainer( | ||
isEnabled: null, | ||
child: child, | ||
), | ||
throwsAssertionError, | ||
); | ||
}, | ||
); | ||
|
||
testWidgets( | ||
"throws an AssertionError if the child parameter is null", | ||
(tester) async { | ||
expect( | ||
() => ManufacturerAdvertisementContainer( | ||
isEnabled: true, | ||
child: null, | ||
), | ||
throwsAssertionError, | ||
); | ||
}, | ||
); | ||
|
||
testWidgets( | ||
"shows the widget passed to the child parameter", | ||
(tester) async { | ||
await tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: ManufacturerAdvertisementContainer( | ||
isEnabled: false, | ||
child: child, | ||
), | ||
), | ||
), | ||
); | ||
|
||
final childWidgetFinder = find.byKey(childKey); | ||
|
||
expect(childWidgetFinder, findsOneWidget); | ||
}, | ||
); | ||
|
||
testWidgets( | ||
"shows the manufacturer banner if isEnabled parameter is true", | ||
(tester) async { | ||
await mockNetworkImagesFor(() { | ||
return tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: ManufacturerAdvertisementContainer( | ||
isEnabled: true, | ||
child: child, | ||
), | ||
), | ||
), | ||
); | ||
}); | ||
|
||
final manufacturerBannerFinder = find.byType(ManufacturerBanner); | ||
|
||
expect(manufacturerBannerFinder, findsOneWidget); | ||
}, | ||
); | ||
|
||
testWidgets( | ||
"does not show the manufacturer banner if isEnabled parameter is false", | ||
(tester) async { | ||
await mockNetworkImagesFor(() { | ||
return tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: ManufacturerAdvertisementContainer( | ||
isEnabled: false, | ||
child: child, | ||
), | ||
), | ||
), | ||
); | ||
}); | ||
|
||
final manufacturerBannerFinder = find.byType(ManufacturerBanner); | ||
|
||
expect(manufacturerBannerFinder, findsNothing); | ||
}, | ||
); | ||
}); | ||
} |
Oops, something went wrong.