component updates
This commit is contained in:
parent
ca88dd1caf
commit
09eb21841a
|
|
@ -49,7 +49,7 @@ class _AudioVisualizerState extends State<AudioVisualizer> {
|
|||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
color: DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.black
|
||||
: Theme.of(context).colorScheme.background,
|
||||
borderRadius: DesignConfig.mediumBorderRadius,
|
||||
|
|
|
|||
|
|
@ -31,8 +31,13 @@ class DidvanButton extends StatelessWidget {
|
|||
foregroundColor = Theme.of(context).colorScheme.text;
|
||||
break;
|
||||
case ButtonStyleMode.flat:
|
||||
if (DesignConfig.isDark) {
|
||||
backgroundColor = Theme.of(context).colorScheme.surface;
|
||||
foregroundColor = Theme.of(context).colorScheme.white;
|
||||
} else {
|
||||
backgroundColor = Theme.of(context).colorScheme.surface;
|
||||
foregroundColor = Theme.of(context).colorScheme.primary;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@ import 'package:flutter/material.dart';
|
|||
|
||||
class DidvanPageView extends StatelessWidget {
|
||||
final List<Widget> pages;
|
||||
const DidvanPageView({Key? key, required this.pages}) : super(key: key);
|
||||
final ScrollController? scrollController;
|
||||
const DidvanPageView({Key? key, required this.pages, this.scrollController})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double deviceTopPadding = MediaQuery.of(context).padding.top;
|
||||
return CarouselSlider.builder(
|
||||
itemCount: 5,
|
||||
itemCount: pages.length,
|
||||
options: CarouselOptions(
|
||||
height: double.infinity,
|
||||
initialPage: 2,
|
||||
|
|
@ -20,16 +22,18 @@ class DidvanPageView extends StatelessWidget {
|
|||
itemBuilder: (context, index, realIndex) => SizedBox(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
left: 4,
|
||||
right: 4,
|
||||
top: 16 + deviceTopPadding,
|
||||
bottom: 92,
|
||||
),
|
||||
child: DidvanCard(
|
||||
padding: EdgeInsets.zero,
|
||||
enableBorder: false,
|
||||
child: pages[0],
|
||||
child: pages[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import 'package:persian_number_utility/persian_number_utility.dart';
|
|||
|
||||
class DidvanTextField extends StatefulWidget {
|
||||
final void Function(String value)? onChanged;
|
||||
final void Function(String value)? onSubmitted;
|
||||
final bool enabled;
|
||||
final bool autoFocus;
|
||||
final TextAlign textAlign;
|
||||
|
|
@ -29,6 +30,7 @@ class DidvanTextField extends StatefulWidget {
|
|||
this.textAlign = TextAlign.right,
|
||||
this.obsecureText = false,
|
||||
this.autoFocus = false,
|
||||
this.onSubmitted,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
|
@ -83,10 +85,9 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
keyboardType: widget.textInputType,
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
onFieldSubmitted: widget.onSubmitted,
|
||||
onChanged: _onChanged,
|
||||
validator: (value) {
|
||||
_validator(value);
|
||||
},
|
||||
validator: _validator,
|
||||
obscuringCharacter: '*',
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
decoration: InputDecoration(
|
||||
|
|
@ -144,7 +145,9 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
|
||||
Color _fillColor() {
|
||||
if (!widget.enabled) {
|
||||
return Theme.of(context).colorScheme.disabledBackground;
|
||||
return DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.disabledBackground
|
||||
: Theme.of(context).colorScheme.secondCTA;
|
||||
}
|
||||
if (_focusNode.hasFocus) {
|
||||
return Theme.of(context).colorScheme.focused;
|
||||
|
|
@ -183,14 +186,13 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<String?> _validator(String? value) async {
|
||||
String? _validator(String? value) {
|
||||
if (widget.validator != null) {
|
||||
final String? error = await widget.validator!(value!);
|
||||
final String? error = widget.validator!(value!);
|
||||
if (error != null) {
|
||||
setState(() {
|
||||
_error = error;
|
||||
});
|
||||
return '';
|
||||
} else {
|
||||
setState(() {
|
||||
_error = null;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,58 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/models/news_details_data.dart';
|
||||
import 'package:didvan/models/radar_details_data.dart';
|
||||
import 'package:didvan/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FloatingNavigationBar extends StatelessWidget {
|
||||
final bool isRadar;
|
||||
const FloatingNavigationBar({Key? key, required this.isRadar})
|
||||
: super(key: key);
|
||||
class FloatingNavigationBar extends StatefulWidget {
|
||||
final RadarDetailsData? radar;
|
||||
final NewsDetailsData? news;
|
||||
final ScrollController scrollController;
|
||||
final VoidCallback bookmarkCallback;
|
||||
const FloatingNavigationBar({
|
||||
Key? key,
|
||||
this.radar,
|
||||
this.news,
|
||||
required this.scrollController,
|
||||
required this.bookmarkCallback,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<FloatingNavigationBar> createState() => _FloatingNavigationBarState();
|
||||
}
|
||||
|
||||
class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
||||
bool _isMarked = false;
|
||||
|
||||
bool get _isRadar => widget.radar != null;
|
||||
bool _isScrolled = false;
|
||||
|
||||
get _item => widget.radar ?? widget.news;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_isMarked = _item.marked;
|
||||
widget.scrollController.addListener(() {
|
||||
final position = widget.scrollController.position.pixels;
|
||||
if (position > 300 && !_isScrolled) {
|
||||
setState(() {
|
||||
_isScrolled = true;
|
||||
});
|
||||
} else if (position < 300 && _isScrolled) {
|
||||
setState(() {
|
||||
_isScrolled = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color foregroundColor =
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
final Color foregroundColor = DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.focusedBorder
|
||||
: Theme.of(context).colorScheme.focused;
|
||||
return Container(
|
||||
|
|
@ -35,20 +76,35 @@ class FloatingNavigationBar extends StatelessWidget {
|
|||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
onPressed: () {
|
||||
if (_isScrolled) {
|
||||
widget.scrollController.animateTo(
|
||||
0,
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
curve: Curves.easeIn,
|
||||
);
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
icon: Icon(
|
||||
_isScrolled ? Icons.arrow_upward : Icons.arrow_back,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
if (isRadar)
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
DidvanIcons.bookmark_regular,
|
||||
if (_isRadar)
|
||||
DidvanIconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isMarked = !_isMarked;
|
||||
});
|
||||
widget.bookmarkCallback();
|
||||
},
|
||||
icon: _isMarked
|
||||
? DidvanIcons.bookmark_solid
|
||||
: DidvanIcons.bookmark_regular,
|
||||
),
|
||||
),
|
||||
if (isRadar)
|
||||
if (_isRadar)
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
|
|
@ -66,19 +122,19 @@ class FloatingNavigationBar extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(
|
||||
DidvanIcons.directs_regular,
|
||||
DidvanIcons.chats_regular,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!isRadar)
|
||||
if (!_isRadar)
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
DidvanIcons.bookmark_regular,
|
||||
),
|
||||
),
|
||||
if (isRadar)
|
||||
if (_isRadar)
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:skeleton_text/skeleton_text.dart';
|
|||
class ShimmerPlaceholder extends StatelessWidget {
|
||||
final double? height;
|
||||
final double? width;
|
||||
final BorderRadius borderRadius;
|
||||
final BorderRadius? borderRadius;
|
||||
|
||||
const ShimmerPlaceholder({
|
||||
Key? key,
|
||||
|
|
@ -18,14 +18,16 @@ class ShimmerPlaceholder extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SkeletonAnimation(
|
||||
borderRadius: borderRadius,
|
||||
borderRadius: borderRadius!,
|
||||
shimmerColor: Theme.of(context).colorScheme.secondCTA,
|
||||
gradientColor: Theme.of(context).colorScheme.cardBorder,
|
||||
child: Container(
|
||||
height: height,
|
||||
width: width,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.disabledBackground,
|
||||
color: DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.focused
|
||||
: Theme.of(context).colorScheme.disabledBackground,
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:didvan/widgets/shimmer_placeholder.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:skeleton_text/skeleton_text.dart';
|
||||
|
||||
class SkeletonImage extends StatelessWidget {
|
||||
class SkeletonImage extends StatefulWidget {
|
||||
final String imageUrl;
|
||||
final double width;
|
||||
final double height;
|
||||
|
|
@ -15,19 +21,61 @@ class SkeletonImage extends StatelessWidget {
|
|||
required this.imageUrl,
|
||||
required this.width,
|
||||
required this.height,
|
||||
this.borderRadius,
|
||||
this.borderRadius = DesignConfig.lowBorderRadius,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SkeletonImage> createState() => _SkeletonImageState();
|
||||
}
|
||||
|
||||
class _SkeletonImageState extends State<SkeletonImage> {
|
||||
Uint8List? _bytes;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (kIsWeb) _getImage();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Future<void> _getImage() async {
|
||||
_bytes = (await http.get(
|
||||
Uri.parse(RequestHelper.baseUrl + widget.imageUrl),
|
||||
headers: {'Authorization': 'Bearer ${RequestService.token}'},
|
||||
))
|
||||
.bodyBytes;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (kIsWeb) {
|
||||
if (_bytes == null || _bytes!.isEmpty) {
|
||||
return ShimmerPlaceholder(
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
borderRadius: widget.borderRadius,
|
||||
);
|
||||
}
|
||||
return ClipRRect(
|
||||
borderRadius: widget.borderRadius,
|
||||
child: Image.memory(
|
||||
_bytes!,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}
|
||||
return CachedNetworkImage(
|
||||
httpHeaders: {'Authorization': 'Bearer ${RequestService.token}'},
|
||||
width: width,
|
||||
height: height,
|
||||
imageUrl: imageUrl,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
imageUrl: RequestHelper.baseUrl + widget.imageUrl,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: borderRadius ?? DesignConfig.lowBorderRadius,
|
||||
borderRadius: widget.borderRadius ?? DesignConfig.lowBorderRadius,
|
||||
image: DecorationImage(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
|
|
@ -36,14 +84,14 @@ class SkeletonImage extends StatelessWidget {
|
|||
),
|
||||
progressIndicatorBuilder: (context, url, progress) => SkeletonAnimation(
|
||||
shimmerColor: Theme.of(context).colorScheme.border,
|
||||
borderRadius: borderRadius ?? DesignConfig.lowBorderRadius,
|
||||
borderRadius: widget.borderRadius ?? DesignConfig.lowBorderRadius,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.disabledBackground,
|
||||
borderRadius: borderRadius,
|
||||
borderRadius: widget.borderRadius,
|
||||
),
|
||||
height: height,
|
||||
width: width,
|
||||
height: widget.height,
|
||||
width: widget.width,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/providers/core_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
|
||||
class StateHandler<T extends CoreProvier> extends StatelessWidget {
|
||||
final T state;
|
||||
final Widget Function(BuildContext context, T state) builder;
|
||||
final VoidCallback? onRefresh;
|
||||
final bool enableCustomLoadingIndicator;
|
||||
final Color? customLoadingIndicatorColor;
|
||||
final bool enableEmptyState;
|
||||
final Widget? placeholder;
|
||||
final Widget? emptyState;
|
||||
final double topPadding;
|
||||
const StateHandler({
|
||||
Key? key,
|
||||
required this.builder,
|
||||
this.emptyState,
|
||||
this.enableCustomLoadingIndicator = false,
|
||||
this.enableEmptyState = false,
|
||||
this.onRefresh,
|
||||
this.topPadding = 0,
|
||||
this.customLoadingIndicatorColor,
|
||||
required this.state,
|
||||
this.placeholder,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
|
@ -38,9 +37,12 @@ class StateHandler<T extends CoreProvier> extends StatelessWidget {
|
|||
case AppState.idle:
|
||||
return builder(context, state);
|
||||
case AppState.busy:
|
||||
return const CircularProgressIndicator();
|
||||
return placeholder ??
|
||||
SpinKitSpinningLines(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
);
|
||||
case AppState.failed:
|
||||
return enableCustomLoadingIndicator ? emptyState! : Container();
|
||||
return Container();
|
||||
default:
|
||||
return Container();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue