Skip to content

Commit

Permalink
Add 'Custom Widgets Documentation'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sofstica-Muhammad-Aun committed Aug 17, 2024
1 parent c75ba32 commit 3936d3f
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 18 deletions.
68 changes: 59 additions & 9 deletions app/lib/global/widgets/ayat_tile/ayat_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,28 @@ import 'package:quran_companion/global/widgets/vertical_gap.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';

/// A widget that displays an Ayat (verse) with various options and translations.
///
/// The `AyatTile` widget includes the Ayat number, Arabic text, Urdu translation,
/// and options for making notes or sharing the Ayat as a PDF. It uses the `AyatTileViewModel`
/// for managing its state and handling user interactions.
class AyatTile extends StatelessWidget {
/// The Ayat (verse) number.
final int number;

/// The Arabic text of the Ayat.
final String arabic;

/// The Urdu translation of the Ayat.
final String urdu;

/// An optional word in the Urdu text to highlight.
final String? highlightedWord;

/// Creates an `AyatTile` widget with the specified properties.
///
/// The [number], [arabic], and [urdu] parameters are required.
/// The [highlightedWord] is optional and can be used to highlight specific words in the Urdu text.
const AyatTile({
super.key,
required this.number,
Expand Down Expand Up @@ -83,7 +100,7 @@ class AyatTile extends StatelessWidget {
const VerticalGap(16),
_UrduText(urdu: urdu, highlightedWord: highlightedWord),
const VerticalGap(34),
const CustomDivider(leftGap: 0, rightGap: 0),
const CustomDivider(leadingIndent: 0, trailingIndent: 0),
],
),
);
Expand All @@ -92,13 +109,18 @@ class AyatTile extends StatelessWidget {
}
}

/// A widget that displays the Ayat number with a styled background.
///
/// This widget is used to visually emphasize the Ayat number within the `AyatTile`.
class _AyatNumber extends StatelessWidget {
/// The Ayat number to display.
final int number;

/// Creates an `_AyatNumber` widget with the specified [number].
const _AyatNumber({
required this.number,
});

final int number;

@override
Widget build(BuildContext context) {
return Tooltip(
Expand All @@ -123,15 +145,23 @@ class _AyatNumber extends StatelessWidget {
}
}

/// A widget that displays the Urdu translation of the Ayat with optional highlighting.
///
/// This widget is used to render the Urdu translation in the `AyatTile`, with an
/// option to highlight a specific word.
class _UrduText extends StatelessWidget {
/// The Urdu translation of the Ayat.
final String urdu;

/// An optional word to highlight within the Urdu text.
final String? highlightedWord;

/// Creates an `_UrduText` widget with the specified [urdu] text and an optional [highlightedWord].
const _UrduText({
required this.urdu,
required this.highlightedWord,
});

final String urdu;
final String? highlightedWord;

@override
Widget build(BuildContext context) {
return SizedBox(
Expand All @@ -148,13 +178,18 @@ class _UrduText extends StatelessWidget {
}
}

/// A widget that displays the Arabic text of the Ayat.
///
/// This widget is used to render the Arabic text in the `AyatTile`, aligning it to the right.
class _ArabicText extends StatelessWidget {
/// The Arabic text of the Ayat.
final String arabic;

/// Creates an `_ArabicText` widget with the specified [arabic] text.
const _ArabicText({
required this.arabic,
});

final String arabic;

@override
Widget build(BuildContext context) {
return SizedBox(
Expand All @@ -170,10 +205,21 @@ class _ArabicText extends StatelessWidget {
}
}

/// A customizable action button used within the `AyatTile`.
///
/// This widget provides an action button with a customizable child widget,
/// tooltip, and tap callback, wrapped in a styled container.
class _CustomActionButton extends StatelessWidget {
/// The widget displayed inside the button.
final Widget child;

/// The callback function triggered when the button is tapped.
final void Function()? onTap;

/// An optional tooltip displayed when the user hovers over the button.
final String? tooltip;

/// Creates a `_CustomActionButton` widget with the specified [child], [onTap] callback, and an optional [tooltip].
const _CustomActionButton({
required this.child,
required this.onTap,
Expand All @@ -198,15 +244,19 @@ class _CustomActionButton extends StatelessWidget {
}
}

/// A custom loading indicator used within action buttons in the `AyatTile`.
///
/// This widget provides a small circular progress indicator, styled to match the app's theme.
class _CustomLoadingIndicator extends StatelessWidget {
/// Creates a `_CustomLoadingIndicator` widget.
const _CustomLoadingIndicator();

@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
width: 13.5.w,
height: 13.5.w,
height: 13.5.h,
child: CircularProgressIndicator(
color: green,
strokeWidth: 2.w,
Expand Down
22 changes: 22 additions & 0 deletions app/lib/global/widgets/custom_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,28 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stacked_services/stacked_services.dart';

/// A customizable app bar widget with a title, subtitle, and back button.
///
/// The `CustomAppBar` widget provides a consistent app bar design featuring
/// a title, subtitle, and back button. It integrates with the `NavigationService`
/// for back navigation and allows for custom titles and subtitles. The app bar
/// also includes a drop shadow and adjusts its layout based on the device's
/// status bar height.
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
/// The navigation service used for handling back navigation.
final NavigationService _navigationService = locator<NavigationService>();

/// The primary title displayed in the app bar.
final String title;

/// The subtitle displayed below the title in the app bar.
final String subtitle;

/// Creates a `CustomAppBar` widget with a [title] and [subtitle].
///
/// The [title] and [subtitle] are required and are displayed prominently
/// in the app bar. The back button is provided by default and is linked
/// to the navigation service for back navigation.
CustomAppBar({
super.key,
required this.title,
Expand All @@ -37,6 +54,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Adds a vertical gap equal to the height of the status bar
VerticalGap(MediaQuery.of(context).viewPadding.top),
Container(
padding: EdgeInsets.only(left: 8.w),
Expand Down Expand Up @@ -77,6 +95,10 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
);
}

/// Specifies the preferred height of the app bar.
///
/// The preferred height is set to the maximum finite size, ensuring the
/// app bar adapts to the content's height.
@override
Size get preferredSize => const Size.fromHeight(double.maxFinite);
}
30 changes: 24 additions & 6 deletions app/lib/global/widgets/custom_divider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,45 @@ import 'package:quran_companion/global/themes/colors.dart';
import 'package:quran_companion/global/widgets/horizontal_gap.dart';
import 'package:flutter/material.dart';

/// A customizable horizontal divider with leading and trailing indents.
///
/// The `CustomDivider` widget creates a horizontal line (divider) with
/// configurable leading and trailing indents. The divider is styled with
/// a specific color and height, and the indents are controlled using
/// [HorizontalGap] widgets.
///
/// This widget is useful for creating visual separations in the UI, where
/// the divider does not span the full width of the container.
class CustomDivider extends StatelessWidget {
final double leftGap;
final double rightGap;
/// The amount of horizontal space before the divider starts.
final double leadingIndent;

/// The amount of horizontal space after the divider ends.
final double trailingIndent;

/// Creates a `CustomDivider` widget with specified [leadingIndent] and [trailingIndent].
///
/// The [leadingIndent] and [trailingIndent] parameters control the padding
/// on either side of the divider, allowing for precise alignment within
/// the layout.
const CustomDivider({
super.key,
required this.leftGap,
required this.rightGap,
required this.leadingIndent,
required this.trailingIndent,
});

@override
Widget build(BuildContext context) {
return Row(
children: [
HorizontalGap(leftGap),
HorizontalGap(leadingIndent),
Expanded(
child: Container(
height: 1,
color: green.withOpacity(0.2),
),
),
HorizontalGap(rightGap),
HorizontalGap(trailingIndent),
],
);
}
Expand Down
27 changes: 26 additions & 1 deletion app/lib/global/widgets/custom_elevated_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,39 @@ import 'package:quran_companion/global/themes/fonts.dart';
import 'package:quran_companion/global/widgets/custom_text.dart';
import 'package:flutter/material.dart';

/// A customizable elevated button with responsive sizing and text styling.
///
/// The `CustomElevatedButton` widget provides a button with customizable
/// dimensions, color, and label. The button's size is responsive to the
/// screen dimensions, and the label is styled using a specified font and size.
///
/// This widget is ideal for creating buttons that fit within a consistent
/// design system while allowing flexibility in appearance.
class CustomElevatedButton extends StatelessWidget {
// TODO: Change to child widget for loading indicator
/// The text label displayed on the button.
final String label;

/// The font size of the label text.
final double labelSize;

/// The callback function triggered when the button is pressed.
final void Function()? onPressed;

/// The background color of the button.
final Color color;

/// The height of the button in logical pixels.
final num height;

/// The width of the button in logical pixels.
final num width;

/// Creates a `CustomElevatedButton` widget with the specified properties.
///
/// The [label], [onPressed], [labelSize], [height], [width], and [color]
/// parameters can be customized to adjust the appearance and behavior of
/// the button. The [labelSize], [height], [width], and [color] have default
/// values, allowing you to create a button with minimal configuration.
const CustomElevatedButton({
super.key,
required this.label,
Expand Down
35 changes: 35 additions & 0 deletions app/lib/global/widgets/custom_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,43 @@ import 'package:quran_companion/global/services/size_helper_service.dart';
import 'package:quran_companion/global/themes/colors.dart';
import 'package:flutter/material.dart';

/// A custom text widget that allows for optional highlighting of a specific word.
///
/// The `CustomText` widget provides a way to display a string of text with
/// optional highlighting of a particular word. If the [highlightedWord] is
/// present in the [data], it will be highlighted with a different background color.
/// This widget supports custom font, size, color, and text alignment.
///
/// This widget is particularly useful when you need to emphasize a part of the
/// text while maintaining a consistent style across the application.
class CustomText extends StatelessWidget {
/// The complete text string to display.
final String data;

/// The font size of the text.
final double size;

/// The font family to use for the text.
final String font;

/// The color of the text.
final Color? color;

/// An optional word to highlight within the text.
///
/// If [highlightedWord] is present in the [data], it will be highlighted
/// with a different background color.
final String? highlightedWord;

/// The alignment of the text.
///
/// Defaults to [TextAlign.left].
final TextAlign textAlign;

/// Creates a `CustomText` widget.
///
/// The [data], [size], and [font] are required. The [color] and [highlightedWord]
/// are optional. The [textAlign] defaults to [TextAlign.left].
const CustomText(
this.data, {
super.key,
Expand All @@ -22,6 +51,8 @@ class CustomText extends StatelessWidget {

@override
Widget build(BuildContext context) {
// If there is no highlighted word or the highlighted word is not found,
// return the text as a simple Text widget.
if (highlightedWord == null || !data.contains(highlightedWord!)) {
return Text(
data,
Expand All @@ -34,9 +65,11 @@ class CustomText extends StatelessWidget {
);
}

// Split the text into parts based on the highlighted word.
final parts = data.split(highlightedWord!);
final spans = <TextSpan>[];

// Build a list of TextSpans, with the highlighted word styled differently.
for (int i = 0; i < parts.length; i++) {
spans.add(
TextSpan(
Expand All @@ -49,6 +82,7 @@ class CustomText extends StatelessWidget {
),
);

// Add the highlighted word between the parts, except after the last part.
if (i < parts.length - 1) {
spans.add(
TextSpan(
Expand All @@ -64,6 +98,7 @@ class CustomText extends StatelessWidget {
}
}

// Return the text as a RichText widget with the appropriate spans.
return RichText(
text: TextSpan(children: spans),
textAlign: textAlign,
Expand Down
15 changes: 15 additions & 0 deletions app/lib/global/widgets/horizontal_gap.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import 'package:flutter/material.dart';
import 'package:quran_companion/global/services/size_helper_service.dart';

/// A widget that provides horizontal spacing between other widgets.
///
/// The `HorizontalGap` widget is a simple wrapper around [SizedBox]
/// that adds horizontal space based on the given [width]. The width
/// is provided in logical pixels and converted to the appropriate
/// responsive width using the `.w` extension.
///
/// This widget is useful for adding consistent horizontal spacing
/// in layouts, especially when using responsive design principles.
class HorizontalGap extends StatelessWidget {
/// The width of the gap in logical pixels.
final double width;

/// Creates a `HorizontalGap` widget with the specified [width].
///
/// The [width] parameter defines the horizontal space this widget
/// will occupy in logical pixels.
const HorizontalGap(this.width, {super.key});

@override
Expand Down
Loading

0 comments on commit 3936d3f

Please sign in to comment.