fontsDownloadWidget method

Widget fontsDownloadWidget(
  1. BuildContext context, {
  2. DownloadFontsDialogStyle? downloadFontsDialogStyle,
  3. String? languageCode,
  4. bool isDark = false,
  5. bool? isFontsLocal = false,
})

A widget that displays the fonts download option.

This widget provides a UI element for downloading fonts.

context is the BuildContext in which the widget is built.

Returns a Widget that represents the fonts download option.

Implementation

Widget fontsDownloadWidget(BuildContext context,
    {DownloadFontsDialogStyle? downloadFontsDialogStyle,
    String? languageCode,
    bool isDark = false,
    bool? isFontsLocal = false}) {
  final ctrl = QuranCtrl.instance;
  final fontsLocal = isFontsLocal ?? false;

  final List<String> titleList = [
    downloadFontsDialogStyle?.defaultFontText ?? 'الخط الأساسي',
    downloadFontsDialogStyle?.downloadedFontsText ?? 'خط المصحف',
  ];

  // Theming fallbacks
  final Color accent =
      downloadFontsDialogStyle?.linearProgressColor ?? Colors.teal;
  final Color background = downloadFontsDialogStyle?.linearProgressColor ??
      AppColors.getBackgroundColor(isDark);
  final Color textColor =
      downloadFontsDialogStyle?.titleColor ?? AppColors.getTextColor(isDark);
  final Color notesColor =
      downloadFontsDialogStyle?.notesColor ?? AppColors.getTextColor(isDark);
  final Color dividerColor = downloadFontsDialogStyle?.dividerColor ?? accent;
  final Color outlineColor =
      (downloadFontsDialogStyle?.downloadButtonBackgroundColor != null)
          ? downloadFontsDialogStyle!.downloadButtonBackgroundColor!
              .withValues(alpha: .2)
          : isDark
              ? accent.withValues(alpha: .35)
              : accent.withValues(alpha: .2);

  Widget buildTile({
    required int index,
  }) {
    final bool isSelected = ctrl.state.fontsSelected.value == index;
    final bool isDownloadOption = index == 1;

    Widget trailingForDownload() {
      if (!isDownloadOption) return const SizedBox.shrink();
      if (fontsLocal) return const SizedBox.shrink();
      return Obx(() {
        final preparing = ctrl.state.isPreparingDownload.value;
        final downloading = ctrl.state.isDownloadingFonts.value;
        final downloaded = ctrl.state.isDownloadedV2Fonts.value;
        // Keep a consistent button area size
        const double buttonHeight = 55;

        return SizedBox(
          width: 40,
          height: isSelected ? 65 : buttonHeight,
          child: Stack(
            alignment: Alignment.center,
            children: [
              if (preparing || downloading)
                SizedBox(
                  width: 22,
                  height: 22,
                  child: CircularProgressIndicator(
                    strokeWidth: 2.2,
                    color: accent,
                  ),
                )
              else
                IconButton(
                  tooltip: downloaded ? 'حذف الخطوط' : 'تحميل الخطوط',
                  onPressed: () async {
                    if (downloaded) {
                      await ctrl.deleteFonts();
                    } else if (!ctrl.state.isDownloadingFonts.value &&
                        !ctrl.state.isPreparingDownload.value) {
                      await ctrl.downloadAllFontsZipFile(index);
                    }
                    log('fontIndex: $index');
                  },
                  icon: downloadFontsDialogStyle?.iconWidget ??
                      Icon(
                        downloaded
                            ? Icons.delete_forever
                            : Icons.download_outlined,
                        color: downloadFontsDialogStyle?.iconColor ?? accent,
                        size: downloadFontsDialogStyle?.iconSize,
                      ),
                ),
            ],
          ),
        );
      });
    }

    Widget progressIndicatorForDownload() {
      if (!isDownloadOption) return const SizedBox.shrink();
      if (fontsLocal) return const SizedBox.shrink();
      return Obx(() {
        final preparing = ctrl.state.isPreparingDownload.value;
        final downloading = ctrl.state.isDownloadingFonts.value;
        final progress = ctrl.state.fontsDownloadProgress.value;

        // Keep a consistent button area size
        const double buttonHeight = 55;
        const double radius = 8;

        final Widget backgroundProgress = ClipRRect(
          borderRadius: BorderRadius.circular(radius),
          child: SizedBox(
            width: double.infinity,
            height: buttonHeight,
            child: TweenAnimationBuilder(
                tween: Tween<double>(
                  begin: 0.0,
                  end: progress,
                ),
                duration: const Duration(milliseconds: 1000),
                curve: Curves.fastEaseInToSlowEaseOut,
                builder: (context, value, child) => LinearProgressIndicator(
                      minHeight: buttonHeight,
                      value: downloading
                          ? (progress / 100).clamp(0.0, 1.0)
                          : null,
                      backgroundColor: (downloadFontsDialogStyle
                                  ?.linearProgressBackgroundColor ??
                              background)
                          .withValues(alpha: .05),
                      valueColor: AlwaysStoppedAnimation<Color>(
                        (downloadFontsDialogStyle?.linearProgressColor ??
                                accent)
                            .withValues(alpha: .25),
                      ),
                    )),
          ),
        );

        return SizedBox(
          width: double.infinity,
          height: buttonHeight,
          child: Stack(
            alignment: Alignment.center,
            children: [
              if (preparing || downloading) backgroundProgress,
            ],
          ),
        );
      });
    }

    return ClipRRect(
      borderRadius: BorderRadius.circular(12.0),
      child: AnimatedContainer(
        height: isSelected ? 65 : 55,
        alignment: Alignment.center,
        duration: const Duration(milliseconds: 200),
        curve: Curves.easeInOut,
        margin: const EdgeInsets.symmetric(vertical: 6.0),
        decoration: BoxDecoration(
          color:
              isSelected ? accent.withValues(alpha: .05) : Colors.transparent,
          border: Border.all(color: outlineColor, width: 1),
          borderRadius: BorderRadius.circular(12.0),
        ),
        child: Obx(() {
          final downloading = ctrl.state.isDownloadingFonts.value;
          final progress = ctrl.state.fontsDownloadProgress.value;
          return Stack(
            alignment: Alignment.center,
            children: [
              progressIndicatorForDownload(),
              ListTile(
                minTileHeight: isSelected ? 65 : 55,
                contentPadding: const EdgeInsetsDirectional.symmetric(
                    horizontal: 12, vertical: 0),
                onTap: (fontsLocal || ctrl.state.isDownloadedV2Fonts.value)
                    ? () {
                        ctrl.state.fontsSelected.value = index;
                        GetStorage()
                            .write(_StorageConstants().fontsSelected, index);
                        log('fontsSelected: ');
                        Get.forceAppUpdate();
                      }
                    : null,
                leading: trailingForDownload(),
                title: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      downloading && isDownloadOption
                          ? '${downloadFontsDialogStyle?.downloadingText ?? 'جاري التحميل'} ${progress.toStringAsFixed(1)}%'
                              .convertNumbersAccordingToLang(
                                  languageCode: languageCode ?? 'ar')
                          : titleList[index],
                      style: downloadFontsDialogStyle?.fontNameStyle ??
                          TextStyle(
                            fontSize: 16,
                            fontFamily: 'cairo',
                            color: textColor,
                            package: 'quran_library',
                          ),
                    ),
                    Icon(
                      isSelected
                          ? Icons.radio_button_checked
                          : Icons.radio_button_unchecked,
                      color: accent,
                    ),
                  ],
                ),
              ),
            ],
          );
        }),
      ),
    );
  }

  return Padding(
    padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      children: [
        // Header
        HeaderDialogWidget(
            title: downloadFontsDialogStyle?.title ?? 'الخطوط'),
        const SizedBox(height: 8.0),
        context.horizontalDivider(
          width: MediaQuery.sizeOf(context).width * .5,
          color: dividerColor,
        ),
        const SizedBox(height: 10.0),
        Text(
          downloadFontsDialogStyle?.notes ??
              'لجعل مظهر المصحف مشابه لمصحف المدينة يمكنك تحميل خطوط المصحف',
          style: downloadFontsDialogStyle?.notesStyle ??
              TextStyle(
                  fontSize: 14.0,
                  fontFamily: 'cairo',
                  color: notesColor,
                  height: 1.5,
                  package: 'quran_library'),
          textAlign: TextAlign.center,
        ),
        const SizedBox(height: 20),

        // Options
        buildTile(index: 0),
        buildTile(index: 1),
      ],
    ),
  );
}