mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 15:23:28 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			606 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			606 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'package:flutter/material.dart';
 | 
						|
import 'package:flutter/services.dart';
 | 
						|
import 'package:obtainium/components/custom_app_bar.dart';
 | 
						|
import 'package:obtainium/components/generated_form.dart';
 | 
						|
import 'package:obtainium/components/generated_form_modal.dart';
 | 
						|
import 'package:obtainium/pages/app.dart';
 | 
						|
import 'package:obtainium/providers/apps_provider.dart';
 | 
						|
import 'package:obtainium/providers/settings_provider.dart';
 | 
						|
import 'package:obtainium/providers/source_provider.dart';
 | 
						|
import 'package:provider/provider.dart';
 | 
						|
import 'package:share_plus/share_plus.dart';
 | 
						|
import 'package:url_launcher/url_launcher_string.dart';
 | 
						|
 | 
						|
class AppsPage extends StatefulWidget {
 | 
						|
  const AppsPage({super.key});
 | 
						|
 | 
						|
  @override
 | 
						|
  State<AppsPage> createState() => AppsPageState();
 | 
						|
}
 | 
						|
 | 
						|
class AppsPageState extends State<AppsPage> {
 | 
						|
  AppsFilter? filter;
 | 
						|
  var updatesOnlyFilter =
 | 
						|
      AppsFilter(includeUptodate: false, includeNonInstalled: false);
 | 
						|
  Set<String> selectedIds = {};
 | 
						|
  DateTime? refreshingSince;
 | 
						|
 | 
						|
  clearSelected() {
 | 
						|
    if (selectedIds.isNotEmpty) {
 | 
						|
      setState(() {
 | 
						|
        selectedIds.clear();
 | 
						|
      });
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  selectThese(List<String> appIds) {
 | 
						|
    if (selectedIds.isEmpty) {
 | 
						|
      setState(() {
 | 
						|
        for (var a in appIds) {
 | 
						|
          selectedIds.add(a);
 | 
						|
        }
 | 
						|
      });
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    var appsProvider = context.watch<AppsProvider>();
 | 
						|
    var settingsProvider = context.watch<SettingsProvider>();
 | 
						|
    var sortedApps = appsProvider.apps.values.toList();
 | 
						|
    var currentFilterIsUpdatesOnly =
 | 
						|
        filter?.isIdenticalTo(updatesOnlyFilter) ?? false;
 | 
						|
 | 
						|
    selectedIds = selectedIds
 | 
						|
        .where((element) => sortedApps.map((e) => e.app.id).contains(element))
 | 
						|
        .toSet();
 | 
						|
 | 
						|
    toggleAppSelected(String appId) {
 | 
						|
      setState(() {
 | 
						|
        if (selectedIds.contains(appId)) {
 | 
						|
          selectedIds.remove(appId);
 | 
						|
        } else {
 | 
						|
          selectedIds.add(appId);
 | 
						|
        }
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    if (filter != null) {
 | 
						|
      sortedApps = sortedApps.where((app) {
 | 
						|
        if (app.app.installedVersion == app.app.latestVersion &&
 | 
						|
            !(filter!.includeUptodate)) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
        if (app.app.installedVersion == null &&
 | 
						|
            !(filter!.includeNonInstalled)) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
        if (filter!.nameFilter.isEmpty && filter!.authorFilter.isEmpty) {
 | 
						|
          return true;
 | 
						|
        }
 | 
						|
        List<String> nameTokens = filter!.nameFilter
 | 
						|
            .split(' ')
 | 
						|
            .where((element) => element.trim().isNotEmpty)
 | 
						|
            .toList();
 | 
						|
        List<String> authorTokens = filter!.authorFilter
 | 
						|
            .split(' ')
 | 
						|
            .where((element) => element.trim().isNotEmpty)
 | 
						|
            .toList();
 | 
						|
 | 
						|
        for (var t in nameTokens) {
 | 
						|
          var name = app.installedInfo?.name ?? app.app.name;
 | 
						|
          if (!name.toLowerCase().contains(t.toLowerCase())) {
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        for (var t in authorTokens) {
 | 
						|
          if (!app.app.author.toLowerCase().contains(t.toLowerCase())) {
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
      }).toList();
 | 
						|
    }
 | 
						|
 | 
						|
    sortedApps.sort((a, b) {
 | 
						|
      var nameA = a.installedInfo?.name ?? a.app.name;
 | 
						|
      var nameB = b.installedInfo?.name ?? b.app.name;
 | 
						|
      int result = 0;
 | 
						|
      if (settingsProvider.sortColumn == SortColumnSettings.authorName) {
 | 
						|
        result = (a.app.author + nameA).compareTo(b.app.author + nameB);
 | 
						|
      } else if (settingsProvider.sortColumn == SortColumnSettings.nameAuthor) {
 | 
						|
        result = (nameA + a.app.author).compareTo(nameB + b.app.author);
 | 
						|
      }
 | 
						|
      return result;
 | 
						|
    });
 | 
						|
 | 
						|
    if (settingsProvider.sortOrder == SortOrderSettings.descending) {
 | 
						|
      sortedApps = sortedApps.reversed.toList();
 | 
						|
    }
 | 
						|
 | 
						|
    var existingUpdates = appsProvider.getExistingUpdates(installedOnly: true);
 | 
						|
 | 
						|
    var existingUpdateIdsAllOrSelected = existingUpdates
 | 
						|
        .where((element) => selectedIds.isEmpty
 | 
						|
            ? sortedApps.where((a) => a.app.id == element).isNotEmpty
 | 
						|
            : selectedIds.contains(element))
 | 
						|
        .toList();
 | 
						|
    var newInstallIdsAllOrSelected = appsProvider
 | 
						|
        .getExistingUpdates(nonInstalledOnly: true)
 | 
						|
        .where((element) => selectedIds.isEmpty
 | 
						|
            ? sortedApps.where((a) => a.app.id == element).isNotEmpty
 | 
						|
            : selectedIds.contains(element))
 | 
						|
        .toList();
 | 
						|
 | 
						|
    if (settingsProvider.pinUpdates) {
 | 
						|
      var temp = [];
 | 
						|
      sortedApps = sortedApps.where((sa) {
 | 
						|
        if (existingUpdates.contains(sa.app.id)) {
 | 
						|
          temp.add(sa);
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
      }).toList();
 | 
						|
      sortedApps = [...temp, ...sortedApps];
 | 
						|
    }
 | 
						|
 | 
						|
    return Scaffold(
 | 
						|
      backgroundColor: Theme.of(context).colorScheme.surface,
 | 
						|
      body: RefreshIndicator(
 | 
						|
          onRefresh: () {
 | 
						|
            HapticFeedback.lightImpact();
 | 
						|
            setState(() {
 | 
						|
              refreshingSince = DateTime.now();
 | 
						|
            });
 | 
						|
            return appsProvider.checkUpdates().catchError((e) {
 | 
						|
              ScaffoldMessenger.of(context).showSnackBar(
 | 
						|
                SnackBar(content: Text(e.toString())),
 | 
						|
              );
 | 
						|
            }).whenComplete(() {
 | 
						|
              setState(() {
 | 
						|
                refreshingSince = null;
 | 
						|
              });
 | 
						|
            });
 | 
						|
          },
 | 
						|
          child: CustomScrollView(slivers: <Widget>[
 | 
						|
            const CustomAppBar(title: 'Apps'),
 | 
						|
            if (appsProvider.loadingApps || sortedApps.isEmpty)
 | 
						|
              SliverFillRemaining(
 | 
						|
                  child: Center(
 | 
						|
                      child: appsProvider.loadingApps
 | 
						|
                          ? const CircularProgressIndicator()
 | 
						|
                          : Text(
 | 
						|
                              appsProvider.apps.isEmpty
 | 
						|
                                  ? 'No Apps'
 | 
						|
                                  : 'No Apps for Filter',
 | 
						|
                              style: Theme.of(context).textTheme.headlineMedium,
 | 
						|
                              textAlign: TextAlign.center,
 | 
						|
                            ))),
 | 
						|
            if (refreshingSince != null)
 | 
						|
              SliverToBoxAdapter(
 | 
						|
                child: LinearProgressIndicator(
 | 
						|
                  value: appsProvider.apps.values
 | 
						|
                          .where((element) => !(element.app.lastUpdateCheck
 | 
						|
                                  ?.isBefore(refreshingSince!) ??
 | 
						|
                              true))
 | 
						|
                          .length /
 | 
						|
                      appsProvider.apps.length,
 | 
						|
                ),
 | 
						|
              ),
 | 
						|
            SliverList(
 | 
						|
                delegate: SliverChildBuilderDelegate(
 | 
						|
                    (BuildContext context, int index) {
 | 
						|
              return ListTile(
 | 
						|
                selectedTileColor:
 | 
						|
                    Theme.of(context).colorScheme.primary.withOpacity(0.1),
 | 
						|
                selected: selectedIds.contains(sortedApps[index].app.id),
 | 
						|
                onLongPress: () {
 | 
						|
                  toggleAppSelected(sortedApps[index].app.id);
 | 
						|
                },
 | 
						|
                leading: sortedApps[index].installedInfo != null
 | 
						|
                    ? Image.memory(
 | 
						|
                        sortedApps[index].installedInfo!.icon!,
 | 
						|
                        gaplessPlayback: true,
 | 
						|
                      )
 | 
						|
                    : null,
 | 
						|
                title: Text(sortedApps[index].installedInfo?.name ??
 | 
						|
                    sortedApps[index].app.name),
 | 
						|
                subtitle: Text('By ${sortedApps[index].app.author}'),
 | 
						|
                trailing: sortedApps[index].downloadProgress != null
 | 
						|
                    ? Text(
 | 
						|
                        'Downloading - ${sortedApps[index].downloadProgress?.toInt()}%')
 | 
						|
                    : (sortedApps[index].app.installedVersion != null &&
 | 
						|
                            sortedApps[index].app.installedVersion !=
 | 
						|
                                sortedApps[index].app.latestVersion
 | 
						|
                        ? Column(
 | 
						|
                            mainAxisAlignment: MainAxisAlignment.center,
 | 
						|
                            crossAxisAlignment: CrossAxisAlignment.end,
 | 
						|
                            children: [
 | 
						|
                              Text(appsProvider.areDownloadsRunning()
 | 
						|
                                  ? 'Please Wait...'
 | 
						|
                                  : 'Update Available'),
 | 
						|
                              SourceProvider()
 | 
						|
                                          .getSource(sortedApps[index].app.url)
 | 
						|
                                          .changeLogPageFromStandardUrl(
 | 
						|
                                              sortedApps[index].app.url) ==
 | 
						|
                                      null
 | 
						|
                                  ? const SizedBox()
 | 
						|
                                  : GestureDetector(
 | 
						|
                                      onTap: () {
 | 
						|
                                        launchUrlString(
 | 
						|
                                            SourceProvider()
 | 
						|
                                                .getSource(
 | 
						|
                                                    sortedApps[index].app.url)
 | 
						|
                                                .changeLogPageFromStandardUrl(
 | 
						|
                                                    sortedApps[index].app.url)!,
 | 
						|
                                            mode:
 | 
						|
                                                LaunchMode.externalApplication);
 | 
						|
                                      },
 | 
						|
                                      child: const Text(
 | 
						|
                                        'See Changes',
 | 
						|
                                        style: TextStyle(
 | 
						|
                                            fontStyle: FontStyle.italic,
 | 
						|
                                            decoration:
 | 
						|
                                                TextDecoration.underline),
 | 
						|
                                      )),
 | 
						|
                            ],
 | 
						|
                          )
 | 
						|
                        : SingleChildScrollView(
 | 
						|
                            child: SizedBox(
 | 
						|
                                width: 80,
 | 
						|
                                child: Text(
 | 
						|
                                  sortedApps[index].app.installedVersion ??
 | 
						|
                                      'Not Installed',
 | 
						|
                                  overflow: TextOverflow.fade,
 | 
						|
                                  textAlign: TextAlign.end,
 | 
						|
                                )))),
 | 
						|
                onTap: () {
 | 
						|
                  if (selectedIds.isNotEmpty) {
 | 
						|
                    toggleAppSelected(sortedApps[index].app.id);
 | 
						|
                  } else {
 | 
						|
                    Navigator.push(
 | 
						|
                      context,
 | 
						|
                      MaterialPageRoute(
 | 
						|
                          builder: (context) =>
 | 
						|
                              AppPage(appId: sortedApps[index].app.id)),
 | 
						|
                    );
 | 
						|
                  }
 | 
						|
                },
 | 
						|
              );
 | 
						|
            }, childCount: sortedApps.length))
 | 
						|
          ])),
 | 
						|
      persistentFooterButtons: [
 | 
						|
        Row(
 | 
						|
          children: [
 | 
						|
            IconButton(
 | 
						|
                onPressed: () {
 | 
						|
                  selectedIds.isEmpty
 | 
						|
                      ? selectThese(sortedApps.map((e) => e.app.id).toList())
 | 
						|
                      : clearSelected();
 | 
						|
                },
 | 
						|
                icon: Icon(
 | 
						|
                  selectedIds.isEmpty
 | 
						|
                      ? Icons.select_all_outlined
 | 
						|
                      : Icons.deselect_outlined,
 | 
						|
                  color: Theme.of(context).colorScheme.primary,
 | 
						|
                ),
 | 
						|
                tooltip: selectedIds.isEmpty
 | 
						|
                    ? 'Select All'
 | 
						|
                    : 'Deselect ${selectedIds.length.toString()}'),
 | 
						|
            const VerticalDivider(),
 | 
						|
            Expanded(
 | 
						|
                child: Row(
 | 
						|
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
						|
              children: [
 | 
						|
                selectedIds.isEmpty
 | 
						|
                    ? const SizedBox()
 | 
						|
                    : IconButton(
 | 
						|
                        visualDensity: VisualDensity.compact,
 | 
						|
                        onPressed: () {
 | 
						|
                          showDialog<List<String>?>(
 | 
						|
                              context: context,
 | 
						|
                              builder: (BuildContext ctx) {
 | 
						|
                                return GeneratedFormModal(
 | 
						|
                                  title: 'Remove Selected Apps?',
 | 
						|
                                  items: const [],
 | 
						|
                                  defaultValues: const [],
 | 
						|
                                  initValid: true,
 | 
						|
                                  message:
 | 
						|
                                      '${selectedIds.length} App${selectedIds.length == 1 ? '' : 's'} will be removed from Obtainium but remain installed. You still need to uninstall ${selectedIds.length == 1 ? 'it' : 'them'} manually.',
 | 
						|
                                );
 | 
						|
                              }).then((values) {
 | 
						|
                            if (values != null) {
 | 
						|
                              appsProvider.removeApps(selectedIds.toList());
 | 
						|
                            }
 | 
						|
                          });
 | 
						|
                        },
 | 
						|
                        tooltip: 'Remove Selected Apps',
 | 
						|
                        icon: const Icon(Icons.delete_outline_outlined),
 | 
						|
                      ),
 | 
						|
                IconButton(
 | 
						|
                    visualDensity: VisualDensity.compact,
 | 
						|
                    onPressed: appsProvider.areDownloadsRunning() ||
 | 
						|
                            (existingUpdateIdsAllOrSelected.isEmpty &&
 | 
						|
                                newInstallIdsAllOrSelected.isEmpty)
 | 
						|
                        ? null
 | 
						|
                        : () {
 | 
						|
                            HapticFeedback.heavyImpact();
 | 
						|
                            List<List<GeneratedFormItem>> formInputs = [];
 | 
						|
                            if (existingUpdateIdsAllOrSelected.isNotEmpty &&
 | 
						|
                                newInstallIdsAllOrSelected.isNotEmpty) {
 | 
						|
                              formInputs.add([
 | 
						|
                                GeneratedFormItem(
 | 
						|
                                    label:
 | 
						|
                                        'Update ${existingUpdateIdsAllOrSelected.length} App${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'}',
 | 
						|
                                    type: FormItemType.bool)
 | 
						|
                              ]);
 | 
						|
                              formInputs.add([
 | 
						|
                                GeneratedFormItem(
 | 
						|
                                    label:
 | 
						|
                                        'Install ${newInstallIdsAllOrSelected.length} new App${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}',
 | 
						|
                                    type: FormItemType.bool)
 | 
						|
                              ]);
 | 
						|
                            }
 | 
						|
                            showDialog<List<String>?>(
 | 
						|
                                context: context,
 | 
						|
                                builder: (BuildContext ctx) {
 | 
						|
                                  return GeneratedFormModal(
 | 
						|
                                    title:
 | 
						|
                                        'Install${selectedIds.isEmpty ? ' ' : ' Selected '}Apps?',
 | 
						|
                                    message:
 | 
						|
                                        '${existingUpdateIdsAllOrSelected.length} update${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'} and ${newInstallIdsAllOrSelected.length} new install${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}.',
 | 
						|
                                    items: formInputs,
 | 
						|
                                    defaultValues: [
 | 
						|
                                      'true',
 | 
						|
                                      existingUpdateIdsAllOrSelected.isEmpty
 | 
						|
                                          ? 'true'
 | 
						|
                                          : ''
 | 
						|
                                    ],
 | 
						|
                                    initValid: true,
 | 
						|
                                  );
 | 
						|
                                }).then((values) {
 | 
						|
                              if (values != null) {
 | 
						|
                                bool shouldInstallUpdates =
 | 
						|
                                    values.isEmpty || values[0] == 'true';
 | 
						|
                                bool shouldInstallNew = values.isEmpty ||
 | 
						|
                                    (values.length >= 2 && values[1] == 'true');
 | 
						|
                                settingsProvider
 | 
						|
                                    .getInstallPermission()
 | 
						|
                                    .then((_) {
 | 
						|
                                  List<String> toInstall = [];
 | 
						|
                                  if (shouldInstallUpdates) {
 | 
						|
                                    toInstall
 | 
						|
                                        .addAll(existingUpdateIdsAllOrSelected);
 | 
						|
                                  }
 | 
						|
                                  if (shouldInstallNew) {
 | 
						|
                                    toInstall
 | 
						|
                                        .addAll(newInstallIdsAllOrSelected);
 | 
						|
                                  }
 | 
						|
                                  appsProvider
 | 
						|
                                      .downloadAndInstallLatestApps(
 | 
						|
                                          toInstall, context)
 | 
						|
                                      .catchError((e) {
 | 
						|
                                    ScaffoldMessenger.of(context).showSnackBar(
 | 
						|
                                      SnackBar(content: Text(e.toString())),
 | 
						|
                                    );
 | 
						|
                                  });
 | 
						|
                                });
 | 
						|
                              }
 | 
						|
                            });
 | 
						|
                          },
 | 
						|
                    tooltip:
 | 
						|
                        'Install/Update${selectedIds.isEmpty ? ' ' : ' Selected '}Apps',
 | 
						|
                    icon: const Icon(
 | 
						|
                      Icons.file_download_outlined,
 | 
						|
                    )),
 | 
						|
                selectedIds.isEmpty
 | 
						|
                    ? const SizedBox()
 | 
						|
                    : IconButton(
 | 
						|
                        visualDensity: VisualDensity.compact,
 | 
						|
                        onPressed: () {
 | 
						|
                          showDialog(
 | 
						|
                              context: context,
 | 
						|
                              builder: (BuildContext ctx) {
 | 
						|
                                return AlertDialog(
 | 
						|
                                  scrollable: true,
 | 
						|
                                  content: Padding(
 | 
						|
                                    padding: const EdgeInsets.only(top: 6),
 | 
						|
                                    child: Row(
 | 
						|
                                        mainAxisAlignment:
 | 
						|
                                            MainAxisAlignment.spaceAround,
 | 
						|
                                        children: [
 | 
						|
                                          IconButton(
 | 
						|
                                              onPressed:
 | 
						|
                                                  appsProvider
 | 
						|
                                                          .areDownloadsRunning()
 | 
						|
                                                      ? null
 | 
						|
                                                      : () {
 | 
						|
                                                          showDialog(
 | 
						|
                                                              context: context,
 | 
						|
                                                              builder:
 | 
						|
                                                                  (BuildContext
 | 
						|
                                                                      ctx) {
 | 
						|
                                                                return AlertDialog(
 | 
						|
                                                                  title: Text(
 | 
						|
                                                                      'Mark ${selectedIds.length} Selected Apps as Updated?'),
 | 
						|
                                                                  content:
 | 
						|
                                                                      const Text(
 | 
						|
                                                                          'Only applies to installed but out of date Apps.'),
 | 
						|
                                                                  actions: [
 | 
						|
                                                                    TextButton(
 | 
						|
                                                                        onPressed:
 | 
						|
                                                                            () {
 | 
						|
                                                                          Navigator.of(context)
 | 
						|
                                                                              .pop();
 | 
						|
                                                                        },
 | 
						|
                                                                        child: const Text(
 | 
						|
                                                                            'No')),
 | 
						|
                                                                    TextButton(
 | 
						|
                                                                        onPressed:
 | 
						|
                                                                            () {
 | 
						|
                                                                          HapticFeedback
 | 
						|
                                                                              .selectionClick();
 | 
						|
                                                                          appsProvider
 | 
						|
                                                                              .saveApps(selectedIds.map((e) {
 | 
						|
                                                                            var a =
 | 
						|
                                                                                appsProvider.apps[e]!.app;
 | 
						|
                                                                            if (a.installedVersion !=
 | 
						|
                                                                                null) {
 | 
						|
                                                                              a.installedVersion = a.latestVersion;
 | 
						|
                                                                            }
 | 
						|
                                                                            return a;
 | 
						|
                                                                          }).toList());
 | 
						|
 | 
						|
                                                                          Navigator.of(context)
 | 
						|
                                                                              .pop();
 | 
						|
                                                                        },
 | 
						|
                                                                        child: const Text(
 | 
						|
                                                                            'Yes'))
 | 
						|
                                                                  ],
 | 
						|
                                                                );
 | 
						|
                                                              });
 | 
						|
                                                        },
 | 
						|
                                              tooltip:
 | 
						|
                                                  'Mark Selected Apps as Updated',
 | 
						|
                                              icon: const Icon(Icons.done)),
 | 
						|
                                          IconButton(
 | 
						|
                                            onPressed: () {
 | 
						|
                                              String urls = '';
 | 
						|
                                              for (var id in selectedIds) {
 | 
						|
                                                urls +=
 | 
						|
                                                    '${appsProvider.apps[id]!.app.url}\n';
 | 
						|
                                              }
 | 
						|
                                              urls = urls.substring(
 | 
						|
                                                  0, urls.length - 1);
 | 
						|
                                              Share.share(urls,
 | 
						|
                                                  subject:
 | 
						|
                                                      '${selectedIds.length} Selected App URLs from Obtainium');
 | 
						|
                                            },
 | 
						|
                                            tooltip: 'Share Selected App URLs',
 | 
						|
                                            icon: const Icon(Icons.share),
 | 
						|
                                          ),
 | 
						|
                                        ]),
 | 
						|
                                  ),
 | 
						|
                                );
 | 
						|
                              });
 | 
						|
                        },
 | 
						|
                        tooltip: 'More',
 | 
						|
                        icon: const Icon(Icons.more_horiz),
 | 
						|
                      ),
 | 
						|
              ],
 | 
						|
            )),
 | 
						|
            const VerticalDivider(),
 | 
						|
            IconButton(
 | 
						|
              visualDensity: VisualDensity.compact,
 | 
						|
              onPressed: () {
 | 
						|
                setState(() {
 | 
						|
                  if (currentFilterIsUpdatesOnly) {
 | 
						|
                    filter = null;
 | 
						|
                  } else {
 | 
						|
                    filter = updatesOnlyFilter;
 | 
						|
                  }
 | 
						|
                });
 | 
						|
              },
 | 
						|
              tooltip: currentFilterIsUpdatesOnly
 | 
						|
                  ? 'Remove Out-of-Date App Filter'
 | 
						|
                  : 'Show Out-of-Date Apps Only',
 | 
						|
              icon: Icon(
 | 
						|
                currentFilterIsUpdatesOnly
 | 
						|
                    ? Icons.update_disabled_rounded
 | 
						|
                    : Icons.update_rounded,
 | 
						|
                color: Theme.of(context).colorScheme.primary,
 | 
						|
              ),
 | 
						|
            ),
 | 
						|
            appsProvider.apps.isEmpty
 | 
						|
                ? const SizedBox()
 | 
						|
                : TextButton.icon(
 | 
						|
                    label: Text(
 | 
						|
                      filter == null ? 'Filter' : 'Filter *',
 | 
						|
                      style: TextStyle(
 | 
						|
                          fontWeight: filter == null
 | 
						|
                              ? FontWeight.normal
 | 
						|
                              : FontWeight.bold),
 | 
						|
                    ),
 | 
						|
                    onPressed: () {
 | 
						|
                      showDialog<List<String>?>(
 | 
						|
                          context: context,
 | 
						|
                          builder: (BuildContext ctx) {
 | 
						|
                            return GeneratedFormModal(
 | 
						|
                                title: 'Filter Apps',
 | 
						|
                                items: [
 | 
						|
                                  [
 | 
						|
                                    GeneratedFormItem(
 | 
						|
                                        label: 'App Name', required: false),
 | 
						|
                                    GeneratedFormItem(
 | 
						|
                                        label: 'Author', required: false)
 | 
						|
                                  ],
 | 
						|
                                  [
 | 
						|
                                    GeneratedFormItem(
 | 
						|
                                        label: 'Up to Date Apps',
 | 
						|
                                        type: FormItemType.bool)
 | 
						|
                                  ],
 | 
						|
                                  [
 | 
						|
                                    GeneratedFormItem(
 | 
						|
                                        label: 'Non-Installed Apps',
 | 
						|
                                        type: FormItemType.bool)
 | 
						|
                                  ]
 | 
						|
                                ],
 | 
						|
                                defaultValues: filter == null
 | 
						|
                                    ? AppsFilter().toValuesArray()
 | 
						|
                                    : filter!.toValuesArray());
 | 
						|
                          }).then((values) {
 | 
						|
                        if (values != null) {
 | 
						|
                          setState(() {
 | 
						|
                            filter = AppsFilter.fromValuesArray(values);
 | 
						|
                            if (AppsFilter().isIdenticalTo(filter!)) {
 | 
						|
                              filter = null;
 | 
						|
                            }
 | 
						|
                          });
 | 
						|
                        }
 | 
						|
                      });
 | 
						|
                    },
 | 
						|
                    icon: const Icon(Icons.filter_list_rounded))
 | 
						|
          ],
 | 
						|
        ),
 | 
						|
      ],
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class AppsFilter {
 | 
						|
  late String nameFilter;
 | 
						|
  late String authorFilter;
 | 
						|
  late bool includeUptodate;
 | 
						|
  late bool includeNonInstalled;
 | 
						|
 | 
						|
  AppsFilter(
 | 
						|
      {this.nameFilter = '',
 | 
						|
      this.authorFilter = '',
 | 
						|
      this.includeUptodate = true,
 | 
						|
      this.includeNonInstalled = true});
 | 
						|
 | 
						|
  List<String> toValuesArray() {
 | 
						|
    return [
 | 
						|
      nameFilter,
 | 
						|
      authorFilter,
 | 
						|
      includeUptodate ? 'true' : '',
 | 
						|
      includeNonInstalled ? 'true' : ''
 | 
						|
    ];
 | 
						|
  }
 | 
						|
 | 
						|
  AppsFilter.fromValuesArray(List<String> values) {
 | 
						|
    nameFilter = values[0];
 | 
						|
    authorFilter = values[1];
 | 
						|
    includeUptodate = values[2] == 'true';
 | 
						|
    includeNonInstalled = values[3] == 'true';
 | 
						|
  }
 | 
						|
 | 
						|
  bool isIdenticalTo(AppsFilter other) =>
 | 
						|
      authorFilter.trim() == other.authorFilter.trim() &&
 | 
						|
      nameFilter.trim() == other.nameFilter.trim() &&
 | 
						|
      includeUptodate == other.includeUptodate &&
 | 
						|
      includeNonInstalled == other.includeNonInstalled;
 | 
						|
}
 |