mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 07:13:28 +01:00 
			
		
		
		
	Compare commits
	
		
			18 Commits
		
	
	
		
			v0.11.17-b
			...
			v0.11.23-b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e8cbac8657 | ||
| 
						 | 
					b66c13d319 | ||
| 
						 | 
					782d055bc3 | ||
| 
						 | 
					d557746965 | ||
| 
						 | 
					e6b05d50b9 | ||
| 
						 | 
					dea635fa6a | ||
| 
						 | 
					682026ed0a | ||
| 
						 | 
					9fe8a200ef | ||
| 
						 | 
					210100da2b | ||
| 
						 | 
					d52660235b | ||
| 
						 | 
					e386b5ab8a | ||
| 
						 | 
					abf7be222d | ||
| 
						 | 
					4c5b9304c0 | ||
| 
						 | 
					4cfe6af044 | ||
| 
						 | 
					3f0c4068dd | ||
| 
						 | 
					7981ca29c5 | ||
| 
						 | 
					187efa8fc5 | ||
| 
						 | 
					cd27ff7f2d | 
@@ -219,7 +219,7 @@
 | 
				
			|||||||
    "importFromURLsInFile": "Importálás fájlban található URL-ből (mint pl. OPML)",
 | 
					    "importFromURLsInFile": "Importálás fájlban található URL-ből (mint pl. OPML)",
 | 
				
			||||||
    "versionDetection": "Verzió érzékelés",
 | 
					    "versionDetection": "Verzió érzékelés",
 | 
				
			||||||
    "standardVersionDetection": "Alapért. verzió érzékelés",
 | 
					    "standardVersionDetection": "Alapért. verzió érzékelés",
 | 
				
			||||||
    "groupByCategory": "Group by Category",
 | 
					    "groupByCategory": "Csoportosítás Kategória alapján",
 | 
				
			||||||
    "removeAppQuestion": {
 | 
					    "removeAppQuestion": {
 | 
				
			||||||
        "one": "Eltávolítja az alkalmazást?",
 | 
					        "one": "Eltávolítja az alkalmazást?",
 | 
				
			||||||
        "other": "Eltávolítja az alkalmazást?"
 | 
					        "other": "Eltávolítja az alkalmazást?"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,12 +14,14 @@ class FDroid extends AppSource {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String standardizeURL(String url) {
 | 
					  String standardizeURL(String url) {
 | 
				
			||||||
    RegExp standardUrlRegExB =
 | 
					    RegExp standardUrlRegExB =
 | 
				
			||||||
        RegExp('^https?://$host/+[^/]+/+packages/+[^/]+');
 | 
					        RegExp('^https?://(cloudflare\\.)?$host/+[^/]+/+packages/+[^/]+');
 | 
				
			||||||
    RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase());
 | 
					    RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase());
 | 
				
			||||||
    if (match != null) {
 | 
					    if (match != null) {
 | 
				
			||||||
      url = 'https://$host/packages/${Uri.parse(url).pathSegments.last}';
 | 
					      url =
 | 
				
			||||||
 | 
					          'https://${Uri.parse(url.substring(0, match.end)).host}/packages/${Uri.parse(url).pathSegments.last}';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    RegExp standardUrlRegExA = RegExp('^https?://$host/+packages/+[^/]+');
 | 
					    RegExp standardUrlRegExA =
 | 
				
			||||||
 | 
					        RegExp('^https?://(cloudflare\\.)?$host/+packages/+[^/]+');
 | 
				
			||||||
    match = standardUrlRegExA.firstMatch(url.toLowerCase());
 | 
					    match = standardUrlRegExA.firstMatch(url.toLowerCase());
 | 
				
			||||||
    if (match == null) {
 | 
					    if (match == null) {
 | 
				
			||||||
      throw InvalidURLError(name);
 | 
					      throw InvalidURLError(name);
 | 
				
			||||||
@@ -61,9 +63,10 @@ class FDroid extends AppSource {
 | 
				
			|||||||
    Map<String, dynamic> additionalSettings,
 | 
					    Map<String, dynamic> additionalSettings,
 | 
				
			||||||
  ) async {
 | 
					  ) async {
 | 
				
			||||||
    String? appId = tryInferringAppId(standardUrl);
 | 
					    String? appId = tryInferringAppId(standardUrl);
 | 
				
			||||||
 | 
					    String host = Uri.parse(standardUrl).host;
 | 
				
			||||||
    return getAPKUrlsFromFDroidPackagesAPIResponse(
 | 
					    return getAPKUrlsFromFDroidPackagesAPIResponse(
 | 
				
			||||||
        await get(Uri.parse('https://f-droid.org/api/v1/packages/$appId')),
 | 
					        await get(Uri.parse('https://$host/api/v1/packages/$appId')),
 | 
				
			||||||
        'https://f-droid.org/repo/$appId',
 | 
					        'https://$host/repo/$appId',
 | 
				
			||||||
        standardUrl);
 | 
					        standardUrl);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -185,9 +185,11 @@ class GitHub extends AppSource {
 | 
				
			|||||||
      Map<String, String> urlsWithDescriptions = {};
 | 
					      Map<String, String> urlsWithDescriptions = {};
 | 
				
			||||||
      for (var e in (jsonDecode(res.body)['items'] as List<dynamic>)) {
 | 
					      for (var e in (jsonDecode(res.body)['items'] as List<dynamic>)) {
 | 
				
			||||||
        urlsWithDescriptions.addAll({
 | 
					        urlsWithDescriptions.addAll({
 | 
				
			||||||
          e['html_url'] as String: e['description'] != null
 | 
					          e['html_url'] as String:
 | 
				
			||||||
              ? e['description'] as String
 | 
					              ((e['archived'] == true ? '[ARCHIVED] ' : '') +
 | 
				
			||||||
              : tr('noDescription')
 | 
					                  (e['description'] != null
 | 
				
			||||||
 | 
					                      ? e['description'] as String
 | 
				
			||||||
 | 
					                      : tr('noDescription')))
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return urlsWithDescriptions;
 | 
					      return urlsWithDescriptions;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
import 'package:html/parser.dart';
 | 
					import 'package:html/parser.dart';
 | 
				
			||||||
import 'package:http/http.dart';
 | 
					import 'package:http/http.dart';
 | 
				
			||||||
import 'package:obtainium/app_sources/github.dart';
 | 
					import 'package:obtainium/app_sources/github.dart';
 | 
				
			||||||
import 'package:obtainium/app_sources/html.dart';
 | 
					 | 
				
			||||||
import 'package:obtainium/custom_errors.dart';
 | 
					import 'package:obtainium/custom_errors.dart';
 | 
				
			||||||
import 'package:obtainium/providers/source_provider.dart';
 | 
					import 'package:obtainium/providers/source_provider.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,24 +28,41 @@ class Mullvad extends AppSource {
 | 
				
			|||||||
    String standardUrl,
 | 
					    String standardUrl,
 | 
				
			||||||
    Map<String, dynamic> additionalSettings,
 | 
					    Map<String, dynamic> additionalSettings,
 | 
				
			||||||
  ) async {
 | 
					  ) async {
 | 
				
			||||||
    var details = await HTML().getLatestAPKDetails(
 | 
					    Response res = await get(Uri.parse('$standardUrl/en/download/android'));
 | 
				
			||||||
        '$standardUrl/en/download/android', additionalSettings);
 | 
					    if (res.statusCode == 200) {
 | 
				
			||||||
    var fileName = details.apkUrls[0].split('/').last;
 | 
					      var versions = parse(res.body)
 | 
				
			||||||
    var versionMatch = RegExp('[0-9]+(\\.[0-9]+)+').firstMatch(fileName);
 | 
					          .querySelectorAll('p')
 | 
				
			||||||
    if (versionMatch == null) {
 | 
					          .map((e) => e.innerHtml)
 | 
				
			||||||
      throw NoVersionError();
 | 
					          .where((p) => p.contains('Latest version: '))
 | 
				
			||||||
 | 
					          .map((e) {
 | 
				
			||||||
 | 
					            var match = RegExp('[0-9]+(\\.[0-9]+)*').firstMatch(e);
 | 
				
			||||||
 | 
					            if (match == null) {
 | 
				
			||||||
 | 
					              return '';
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              return e.substring(match.start, match.end);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .where((element) => element.isNotEmpty)
 | 
				
			||||||
 | 
					          .toList();
 | 
				
			||||||
 | 
					      if (versions.isEmpty) {
 | 
				
			||||||
 | 
					        throw NoVersionError();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      String? changeLog;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        changeLog = (await GitHub().getLatestAPKDetails(
 | 
				
			||||||
 | 
					                'https://github.com/mullvad/mullvadvpn-app',
 | 
				
			||||||
 | 
					                {'fallbackToOlderReleases': true}))
 | 
				
			||||||
 | 
					            .changeLog;
 | 
				
			||||||
 | 
					      } catch (e) {
 | 
				
			||||||
 | 
					        // Ignore
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return APKDetails(
 | 
				
			||||||
 | 
					          versions[0],
 | 
				
			||||||
 | 
					          ['https://mullvad.net/download/app/apk/latest'],
 | 
				
			||||||
 | 
					          AppNames(name, 'Mullvad-VPN'),
 | 
				
			||||||
 | 
					          changeLog: changeLog);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw getObtainiumHttpError(res);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    details.version = fileName.substring(versionMatch.start, versionMatch.end);
 | 
					 | 
				
			||||||
    details.names = AppNames(name, 'Mullvad-VPN');
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      details.changeLog = (await GitHub().getLatestAPKDetails(
 | 
					 | 
				
			||||||
              'https://github.com/mullvad/mullvadvpn-app',
 | 
					 | 
				
			||||||
              {'fallbackToOlderReleases': true}))
 | 
					 | 
				
			||||||
          .changeLog;
 | 
					 | 
				
			||||||
    } catch (e) {
 | 
					 | 
				
			||||||
      print(e);
 | 
					 | 
				
			||||||
      // Ignore
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return details;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart';
 | 
				
			|||||||
// ignore: implementation_imports
 | 
					// ignore: implementation_imports
 | 
				
			||||||
import 'package:easy_localization/src/localization.dart';
 | 
					import 'package:easy_localization/src/localization.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const String currentVersion = '0.11.17';
 | 
					const String currentVersion = '0.11.23';
 | 
				
			||||||
const String currentReleaseTag =
 | 
					const String currentReleaseTag =
 | 
				
			||||||
    'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
 | 
					    'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -334,11 +334,10 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
				
			|||||||
          ],
 | 
					          ],
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Widget getSourcesListWidget() => Expanded(
 | 
					    Widget getSourcesListWidget() => Column(
 | 
				
			||||||
            child: Column(
 | 
					            crossAxisAlignment: CrossAxisAlignment.center,
 | 
				
			||||||
                crossAxisAlignment: CrossAxisAlignment.center,
 | 
					            mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
                mainAxisAlignment: MainAxisAlignment.center,
 | 
					            children: [
 | 
				
			||||||
                children: [
 | 
					 | 
				
			||||||
              const SizedBox(
 | 
					              const SizedBox(
 | 
				
			||||||
                height: 48,
 | 
					                height: 48,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
@@ -365,16 +364,17 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
				
			|||||||
                            fontStyle: FontStyle.italic),
 | 
					                            fontStyle: FontStyle.italic),
 | 
				
			||||||
                      )))
 | 
					                      )))
 | 
				
			||||||
                  .toList()
 | 
					                  .toList()
 | 
				
			||||||
            ]));
 | 
					            ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
        backgroundColor: Theme.of(context).colorScheme.surface,
 | 
					        backgroundColor: Theme.of(context).colorScheme.surface,
 | 
				
			||||||
        body: CustomScrollView(slivers: <Widget>[
 | 
					        body: CustomScrollView(shrinkWrap: true, slivers: <Widget>[
 | 
				
			||||||
          CustomAppBar(title: tr('addApp')),
 | 
					          CustomAppBar(title: tr('addApp')),
 | 
				
			||||||
          SliverFillRemaining(
 | 
					          SliverToBoxAdapter(
 | 
				
			||||||
            child: Padding(
 | 
					            child: Padding(
 | 
				
			||||||
                padding: const EdgeInsets.all(16),
 | 
					                padding: const EdgeInsets.all(16),
 | 
				
			||||||
                child: Column(
 | 
					                child: Column(
 | 
				
			||||||
 | 
					                    mainAxisSize: MainAxisSize.min,
 | 
				
			||||||
                    crossAxisAlignment: CrossAxisAlignment.stretch,
 | 
					                    crossAxisAlignment: CrossAxisAlignment.stretch,
 | 
				
			||||||
                    children: [
 | 
					                    children: [
 | 
				
			||||||
                      getUrlInputRow(),
 | 
					                      getUrlInputRow(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@ class _AppPageState extends State<AppPage> {
 | 
				
			|||||||
              height: 25,
 | 
					              height: 25,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Text(
 | 
					            Text(
 | 
				
			||||||
              app?.installedInfo?.name ?? app?.app.name ?? tr('app'),
 | 
					              app?.app.name ?? tr('app'),
 | 
				
			||||||
              textAlign: TextAlign.center,
 | 
					              textAlign: TextAlign.center,
 | 
				
			||||||
              style: Theme.of(context).textTheme.displayLarge,
 | 
					              style: Theme.of(context).textTheme.displayLarge,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@ class AppsPageState extends State<AppsPage> {
 | 
				
			|||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    var appsProvider = context.watch<AppsProvider>();
 | 
					    var appsProvider = context.watch<AppsProvider>();
 | 
				
			||||||
    var settingsProvider = context.watch<SettingsProvider>();
 | 
					    var settingsProvider = context.watch<SettingsProvider>();
 | 
				
			||||||
 | 
					    var sourceProvider = SourceProvider();
 | 
				
			||||||
    var listedApps = appsProvider.apps.values.toList();
 | 
					    var listedApps = appsProvider.apps.values.toList();
 | 
				
			||||||
    var currentFilterIsUpdatesOnly =
 | 
					    var currentFilterIsUpdatesOnly =
 | 
				
			||||||
        filter.isIdenticalTo(updatesOnlyFilter, settingsProvider);
 | 
					        filter.isIdenticalTo(updatesOnlyFilter, settingsProvider);
 | 
				
			||||||
@@ -110,6 +111,11 @@ class AppsPageState extends State<AppsPage> {
 | 
				
			|||||||
              .isEmpty) {
 | 
					              .isEmpty) {
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      if (filter.sourceFilter.isNotEmpty &&
 | 
				
			||||||
 | 
					          sourceProvider.getSource(app.app.url).runtimeType.toString() !=
 | 
				
			||||||
 | 
					              filter.sourceFilter) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }).toList();
 | 
					    }).toList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -448,7 +454,8 @@ class AppsPageState extends State<AppsPage> {
 | 
				
			|||||||
                    .app
 | 
					                    .app
 | 
				
			||||||
                    .categories
 | 
					                    .categories
 | 
				
			||||||
                    .map((e) =>
 | 
					                    .map((e) =>
 | 
				
			||||||
                        Color(settingsProvider.categories[e]!).withAlpha(255))
 | 
					                        Color(settingsProvider.categories[e] ?? transparent)
 | 
				
			||||||
 | 
					                            .withAlpha(255))
 | 
				
			||||||
                    .toList(),
 | 
					                    .toList(),
 | 
				
			||||||
                Color(transparent)
 | 
					                Color(transparent)
 | 
				
			||||||
              ])),
 | 
					              ])),
 | 
				
			||||||
@@ -734,14 +741,12 @@ class AppsPageState extends State<AppsPage> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pinSelectedApps() {
 | 
					    pinSelectedApps() {
 | 
				
			||||||
      () {
 | 
					      var pinStatus = selectedApps.where((element) => element.pinned).isEmpty;
 | 
				
			||||||
        var pinStatus = selectedApps.where((element) => element.pinned).isEmpty;
 | 
					      appsProvider.saveApps(selectedApps.map((e) {
 | 
				
			||||||
        appsProvider.saveApps(selectedApps.map((e) {
 | 
					        e.pinned = pinStatus;
 | 
				
			||||||
          e.pinned = pinStatus;
 | 
					        return e;
 | 
				
			||||||
          return e;
 | 
					      }).toList());
 | 
				
			||||||
        }).toList());
 | 
					      Navigator.of(context).pop();
 | 
				
			||||||
        Navigator.of(context).pop();
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    resetSelectedAppsInstallStatuses() {
 | 
					    resetSelectedAppsInstallStatuses() {
 | 
				
			||||||
@@ -893,6 +898,19 @@ class AppsPageState extends State<AppsPage> {
 | 
				
			|||||||
                  GeneratedFormSwitch('nonInstalledApps',
 | 
					                  GeneratedFormSwitch('nonInstalledApps',
 | 
				
			||||||
                      label: tr('nonInstalledApps'),
 | 
					                      label: tr('nonInstalledApps'),
 | 
				
			||||||
                      defaultValue: vals['nonInstalledApps'])
 | 
					                      defaultValue: vals['nonInstalledApps'])
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                  GeneratedFormDropdown(
 | 
				
			||||||
 | 
					                      'sourceFilter',
 | 
				
			||||||
 | 
					                      label: tr('appSource'),
 | 
				
			||||||
 | 
					                      defaultValue: filter.sourceFilter,
 | 
				
			||||||
 | 
					                      [
 | 
				
			||||||
 | 
					                        MapEntry('', tr('none')),
 | 
				
			||||||
 | 
					                        ...sourceProvider.sources
 | 
				
			||||||
 | 
					                            .map((e) =>
 | 
				
			||||||
 | 
					                                MapEntry(e.runtimeType.toString(), e.name))
 | 
				
			||||||
 | 
					                            .toList()
 | 
				
			||||||
 | 
					                      ])
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
              additionalWidgets: [
 | 
					              additionalWidgets: [
 | 
				
			||||||
@@ -1016,20 +1034,23 @@ class AppsFilter {
 | 
				
			|||||||
  late bool includeUptodate;
 | 
					  late bool includeUptodate;
 | 
				
			||||||
  late bool includeNonInstalled;
 | 
					  late bool includeNonInstalled;
 | 
				
			||||||
  late Set<String> categoryFilter;
 | 
					  late Set<String> categoryFilter;
 | 
				
			||||||
 | 
					  late String sourceFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AppsFilter(
 | 
					  AppsFilter(
 | 
				
			||||||
      {this.nameFilter = '',
 | 
					      {this.nameFilter = '',
 | 
				
			||||||
      this.authorFilter = '',
 | 
					      this.authorFilter = '',
 | 
				
			||||||
      this.includeUptodate = true,
 | 
					      this.includeUptodate = true,
 | 
				
			||||||
      this.includeNonInstalled = true,
 | 
					      this.includeNonInstalled = true,
 | 
				
			||||||
      this.categoryFilter = const {}});
 | 
					      this.categoryFilter = const {},
 | 
				
			||||||
 | 
					      this.sourceFilter = ''});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toFormValuesMap() {
 | 
					  Map<String, dynamic> toFormValuesMap() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      'appName': nameFilter,
 | 
					      'appName': nameFilter,
 | 
				
			||||||
      'author': authorFilter,
 | 
					      'author': authorFilter,
 | 
				
			||||||
      'upToDateApps': includeUptodate,
 | 
					      'upToDateApps': includeUptodate,
 | 
				
			||||||
      'nonInstalledApps': includeNonInstalled
 | 
					      'nonInstalledApps': includeNonInstalled,
 | 
				
			||||||
 | 
					      'sourceFilter': sourceFilter
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1038,6 +1059,7 @@ class AppsFilter {
 | 
				
			|||||||
    authorFilter = values['author']!;
 | 
					    authorFilter = values['author']!;
 | 
				
			||||||
    includeUptodate = values['upToDateApps'];
 | 
					    includeUptodate = values['upToDateApps'];
 | 
				
			||||||
    includeNonInstalled = values['nonInstalledApps'];
 | 
					    includeNonInstalled = values['nonInstalledApps'];
 | 
				
			||||||
 | 
					    sourceFilter = values['sourceFilter'];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool isIdenticalTo(AppsFilter other, SettingsProvider settingsProvider) =>
 | 
					  bool isIdenticalTo(AppsFilter other, SettingsProvider settingsProvider) =>
 | 
				
			||||||
@@ -1045,5 +1067,6 @@ class AppsFilter {
 | 
				
			|||||||
      nameFilter.trim() == other.nameFilter.trim() &&
 | 
					      nameFilter.trim() == other.nameFilter.trim() &&
 | 
				
			||||||
      includeUptodate == other.includeUptodate &&
 | 
					      includeUptodate == other.includeUptodate &&
 | 
				
			||||||
      includeNonInstalled == other.includeNonInstalled &&
 | 
					      includeNonInstalled == other.includeNonInstalled &&
 | 
				
			||||||
      settingsProvider.setEqual(categoryFilter, other.categoryFilter);
 | 
					      settingsProvider.setEqual(categoryFilter, other.categoryFilter) &&
 | 
				
			||||||
 | 
					      sourceFilter.trim() == other.sourceFilter.trim();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -133,7 +133,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            settingsProvider.categories = cats;
 | 
					            appsProvider.addMissingCategories(settingsProvider);
 | 
				
			||||||
            showError(tr('importedX', args: [plural('apps', value)]), context);
 | 
					            showError(tr('importedX', args: [plural('apps', value)]), context);
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import 'package:obtainium/components/custom_app_bar.dart';
 | 
				
			|||||||
import 'package:obtainium/components/generated_form.dart';
 | 
					import 'package:obtainium/components/generated_form.dart';
 | 
				
			||||||
import 'package:obtainium/custom_errors.dart';
 | 
					import 'package:obtainium/custom_errors.dart';
 | 
				
			||||||
import 'package:obtainium/main.dart';
 | 
					import 'package:obtainium/main.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/apps_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/logs_provider.dart';
 | 
					import 'package:obtainium/providers/logs_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/settings_provider.dart';
 | 
					import 'package:obtainium/providers/settings_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/source_provider.dart';
 | 
					import 'package:obtainium/providers/source_provider.dart';
 | 
				
			||||||
@@ -444,6 +445,7 @@ class _CategoryEditorSelectorState extends State<CategoryEditorSelector> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    var settingsProvider = context.watch<SettingsProvider>();
 | 
					    var settingsProvider = context.watch<SettingsProvider>();
 | 
				
			||||||
 | 
					    var appsProvider = context.watch<AppsProvider>();
 | 
				
			||||||
    storedValues = settingsProvider.categories.map((key, value) => MapEntry(
 | 
					    storedValues = settingsProvider.categories.map((key, value) => MapEntry(
 | 
				
			||||||
        key,
 | 
					        key,
 | 
				
			||||||
        MapEntry(value,
 | 
					        MapEntry(value,
 | 
				
			||||||
@@ -467,8 +469,9 @@ class _CategoryEditorSelectorState extends State<CategoryEditorSelector> {
 | 
				
			|||||||
          if (!isBuilding) {
 | 
					          if (!isBuilding) {
 | 
				
			||||||
            storedValues =
 | 
					            storedValues =
 | 
				
			||||||
                values['categories'] as Map<String, MapEntry<int, bool>>;
 | 
					                values['categories'] as Map<String, MapEntry<int, bool>>;
 | 
				
			||||||
            settingsProvider.categories =
 | 
					            settingsProvider.setCategories(
 | 
				
			||||||
                storedValues.map((key, value) => MapEntry(key, value.key));
 | 
					                storedValues.map((key, value) => MapEntry(key, value.key)),
 | 
				
			||||||
 | 
					                appsProvider: appsProvider);
 | 
				
			||||||
            if (widget.onSelected != null) {
 | 
					            if (widget.onSelected != null) {
 | 
				
			||||||
              widget.onSelected!(storedValues.keys
 | 
					              widget.onSelected!(storedValues.keys
 | 
				
			||||||
                  .where((k) => storedValues[k]!.value)
 | 
					                  .where((k) => storedValues[k]!.value)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -670,6 +670,9 @@ class AppsProvider with ChangeNotifier {
 | 
				
			|||||||
    for (var app in apps) {
 | 
					    for (var app in apps) {
 | 
				
			||||||
      AppInfo? info = await getInstalledInfo(app.id);
 | 
					      AppInfo? info = await getInstalledInfo(app.id);
 | 
				
			||||||
      app.name = info?.name ?? app.name;
 | 
					      app.name = info?.name ?? app.name;
 | 
				
			||||||
 | 
					      if (app.additionalSettings['appName']?.toString().isNotEmpty == true) {
 | 
				
			||||||
 | 
					        app.name = app.additionalSettings['appName'].toString().trim();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      if (attemptToCorrectInstallStatus) {
 | 
					      if (attemptToCorrectInstallStatus) {
 | 
				
			||||||
        app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
 | 
					        app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -757,6 +760,18 @@ class AppsProvider with ChangeNotifier {
 | 
				
			|||||||
    await intent.launch();
 | 
					    await intent.launch();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addMissingCategories(SettingsProvider settingsProvider) {
 | 
				
			||||||
 | 
					    var cats = settingsProvider.categories;
 | 
				
			||||||
 | 
					    apps.forEach((key, value) {
 | 
				
			||||||
 | 
					      for (var c in value.app.categories) {
 | 
				
			||||||
 | 
					        if (!cats.containsKey(c)) {
 | 
				
			||||||
 | 
					          cats[c] = generateRandomLightColor().value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    settingsProvider.setCategories(cats, appsProvider: this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<App?> checkUpdate(String appId) async {
 | 
					  Future<App?> checkUpdate(String appId) async {
 | 
				
			||||||
    App? currentApp = apps[appId]!.app;
 | 
					    App? currentApp = apps[appId]!.app;
 | 
				
			||||||
    SourceProvider sourceProvider = SourceProvider();
 | 
					    SourceProvider sourceProvider = SourceProvider();
 | 
				
			||||||
@@ -836,12 +851,6 @@ class AppsProvider with ChangeNotifier {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<String> exportApps() async {
 | 
					  Future<String> exportApps() async {
 | 
				
			||||||
    Directory? exportDir = Directory('/storage/emulated/0/Download');
 | 
					 | 
				
			||||||
    String path = 'Downloads'; // TODO: See if hardcoding this can be avoided
 | 
					 | 
				
			||||||
    if (!exportDir.existsSync()) {
 | 
					 | 
				
			||||||
      exportDir = await getExternalStorageDirectory();
 | 
					 | 
				
			||||||
      path = exportDir!.path;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if ((await DeviceInfoPlugin().androidInfo).version.sdkInt <= 29) {
 | 
					    if ((await DeviceInfoPlugin().androidInfo).version.sdkInt <= 29) {
 | 
				
			||||||
      if (await Permission.storage.isDenied) {
 | 
					      if (await Permission.storage.isDenied) {
 | 
				
			||||||
        await Permission.storage.request();
 | 
					        await Permission.storage.request();
 | 
				
			||||||
@@ -850,6 +859,18 @@ class AppsProvider with ChangeNotifier {
 | 
				
			|||||||
        throw ObtainiumError(tr('storagePermissionDenied'));
 | 
					        throw ObtainiumError(tr('storagePermissionDenied'));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    Directory? exportDir = Directory('/storage/emulated/0/Download');
 | 
				
			||||||
 | 
					    String path = 'Downloads'; // TODO: See if hardcoding this can be avoided
 | 
				
			||||||
 | 
					    var downloadsAccessible = false;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      downloadsAccessible = exportDir.existsSync();
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      logs.add('Error accessing Downloads (will use fallback): $e');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!downloadsAccessible) {
 | 
				
			||||||
 | 
					      exportDir = await getExternalStorageDirectory();
 | 
				
			||||||
 | 
					      path = exportDir!.path;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    File export = File(
 | 
					    File export = File(
 | 
				
			||||||
        '${exportDir.path}/${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().millisecondsSinceEpoch}.json');
 | 
					        '${exportDir.path}/${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().millisecondsSinceEpoch}.json');
 | 
				
			||||||
    export.writeAsStringSync(
 | 
					    export.writeAsStringSync(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import 'package:flutter/material.dart';
 | 
				
			|||||||
import 'package:fluttertoast/fluttertoast.dart';
 | 
					import 'package:fluttertoast/fluttertoast.dart';
 | 
				
			||||||
import 'package:obtainium/app_sources/github.dart';
 | 
					import 'package:obtainium/app_sources/github.dart';
 | 
				
			||||||
import 'package:obtainium/main.dart';
 | 
					import 'package:obtainium/main.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/apps_provider.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/source_provider.dart';
 | 
				
			||||||
import 'package:permission_handler/permission_handler.dart';
 | 
					import 'package:permission_handler/permission_handler.dart';
 | 
				
			||||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
					import 'package:shared_preferences/shared_preferences.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,7 +162,22 @@ class SettingsProvider with ChangeNotifier {
 | 
				
			|||||||
  Map<String, int> get categories =>
 | 
					  Map<String, int> get categories =>
 | 
				
			||||||
      Map<String, int>.from(jsonDecode(prefs?.getString('categories') ?? '{}'));
 | 
					      Map<String, int>.from(jsonDecode(prefs?.getString('categories') ?? '{}'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  set categories(Map<String, int> cats) {
 | 
					  void setCategories(Map<String, int> cats, {AppsProvider? appsProvider}) {
 | 
				
			||||||
 | 
					    if (appsProvider != null) {
 | 
				
			||||||
 | 
					      List<App> changedApps = appsProvider.apps.values
 | 
				
			||||||
 | 
					          .map((a) {
 | 
				
			||||||
 | 
					            var n1 = a.app.categories.length;
 | 
				
			||||||
 | 
					            a.app.categories.removeWhere((c) => !cats.keys.contains(c));
 | 
				
			||||||
 | 
					            return n1 > a.app.categories.length ? a.app : null;
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .where((element) => element != null)
 | 
				
			||||||
 | 
					          .map((e) => e as App)
 | 
				
			||||||
 | 
					          .toList();
 | 
				
			||||||
 | 
					      if (changedApps.isNotEmpty) {
 | 
				
			||||||
 | 
					        appsProvider.saveApps(changedApps,
 | 
				
			||||||
 | 
					            attemptToCorrectInstallStatus: false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    prefs?.setString('categories', jsonEncode(cats));
 | 
					    prefs?.setString('categories', jsonEncode(cats));
 | 
				
			||||||
    notifyListeners();
 | 
					    notifyListeners();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -278,7 +278,8 @@ class AppSource {
 | 
				
			|||||||
              return regExValidator(value);
 | 
					              return regExValidator(value);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          ])
 | 
					          ])
 | 
				
			||||||
    ]
 | 
					    ],
 | 
				
			||||||
 | 
					    [GeneratedFormTextField('appName', label: tr('appName'), required: false)]
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Previous 2 variables combined into one at runtime for convenient usage
 | 
					  // Previous 2 variables combined into one at runtime for convenient usage
 | 
				
			||||||
@@ -362,7 +363,7 @@ class SourceProvider {
 | 
				
			|||||||
    url = preStandardizeUrl(url);
 | 
					    url = preStandardizeUrl(url);
 | 
				
			||||||
    AppSource? source;
 | 
					    AppSource? source;
 | 
				
			||||||
    for (var s in sources.where((element) => element.host != null)) {
 | 
					    for (var s in sources.where((element) => element.host != null)) {
 | 
				
			||||||
      if (url.contains('://${s.host}')) {
 | 
					      if (RegExp('://(.+\\.)?${s.host}').hasMatch(url)) {
 | 
				
			||||||
        source = s;
 | 
					        source = s;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -427,8 +428,10 @@ class SourceProvider {
 | 
				
			|||||||
      throw NoAPKError();
 | 
					      throw NoAPKError();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    String apkVersion = apk.version.replaceAll('/', '-');
 | 
					    String apkVersion = apk.version.replaceAll('/', '-');
 | 
				
			||||||
    var name = currentApp?.name.trim() ??
 | 
					    var name = currentApp != null ? currentApp.name.trim() : '';
 | 
				
			||||||
        apk.names.name[0].toUpperCase() + apk.names.name.substring(1);
 | 
					    name = name.isNotEmpty
 | 
				
			||||||
 | 
					        ? name
 | 
				
			||||||
 | 
					        : apk.names.name[0].toUpperCase() + apk.names.name.substring(1);
 | 
				
			||||||
    return App(
 | 
					    return App(
 | 
				
			||||||
        currentApp?.id ??
 | 
					        currentApp?.id ??
 | 
				
			||||||
            source.tryInferringAppId(standardUrl,
 | 
					            source.tryInferringAppId(standardUrl,
 | 
				
			||||||
@@ -436,9 +439,7 @@ class SourceProvider {
 | 
				
			|||||||
            generateTempID(standardUrl, additionalSettings),
 | 
					            generateTempID(standardUrl, additionalSettings),
 | 
				
			||||||
        standardUrl,
 | 
					        standardUrl,
 | 
				
			||||||
        apk.names.author[0].toUpperCase() + apk.names.author.substring(1),
 | 
					        apk.names.author[0].toUpperCase() + apk.names.author.substring(1),
 | 
				
			||||||
        name.trim().isNotEmpty
 | 
					        name,
 | 
				
			||||||
            ? name
 | 
					 | 
				
			||||||
            : apk.names.name[0].toUpperCase() + apk.names.name.substring(1),
 | 
					 | 
				
			||||||
        currentApp?.installedVersion,
 | 
					        currentApp?.installedVersion,
 | 
				
			||||||
        apkVersion,
 | 
					        apkVersion,
 | 
				
			||||||
        apk.apkUrls,
 | 
					        apk.apkUrls,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								pubspec.lock
									
									
									
									
									
								
							@@ -337,10 +337,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: markdown
 | 
					      name: markdown
 | 
				
			||||||
      sha256: b3c60dee8c2af50ad0e6e90cceba98e47718a6ee0a7a6772c77846a0cc21f78b
 | 
					      sha256: d95a9d12954aafc97f984ca29baaa7690ed4d9ec4140a23ad40580bcdb6c87f5
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "7.0.1"
 | 
					    version: "7.0.2"
 | 
				
			||||||
  matcher:
 | 
					  matcher:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -553,34 +553,34 @@ packages:
 | 
				
			|||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences
 | 
					      name: shared_preferences
 | 
				
			||||||
      sha256: "78528fd87d0d08ffd3e69551173c026e8eacc7b7079c82eb6a77413957b7e394"
 | 
					      sha256: "858aaa72d8f61637d64e776aca82e1c67e6d9ee07979123c5d17115031c1b13b"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.0.20"
 | 
					    version: "2.1.0"
 | 
				
			||||||
  shared_preferences_android:
 | 
					  shared_preferences_android:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences_android
 | 
					      name: shared_preferences_android
 | 
				
			||||||
      sha256: ad423a80fe7b4e48b50d6111b3ea1027af0e959e49d485712e134863d9c1c521
 | 
					      sha256: "8304d8a1f7d21a429f91dee552792249362b68a331ac5c3c1caf370f658873f6"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.0.17"
 | 
					    version: "2.1.0"
 | 
				
			||||||
  shared_preferences_foundation:
 | 
					  shared_preferences_foundation:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences_foundation
 | 
					      name: shared_preferences_foundation
 | 
				
			||||||
      sha256: "1e755f8583229f185cfca61b1d80fb2344c9d660e1c69ede5450d8f478fa5310"
 | 
					      sha256: cf2a42fb20148502022861f71698db12d937c7459345a1bdaa88fc91a91b3603
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.5"
 | 
					    version: "2.2.0"
 | 
				
			||||||
  shared_preferences_linux:
 | 
					  shared_preferences_linux:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences_linux
 | 
					      name: shared_preferences_linux
 | 
				
			||||||
      sha256: "3a59ed10890a8409ad0faad7bb2957dab4b92b8fbe553257b05d30ed8af2c707"
 | 
					      sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.5"
 | 
					    version: "2.2.0"
 | 
				
			||||||
  shared_preferences_platform_interface:
 | 
					  shared_preferences_platform_interface:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -593,18 +593,18 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences_web
 | 
					      name: shared_preferences_web
 | 
				
			||||||
      sha256: "0dc2633f215a3d4aa3184c9b2c5766f4711e4e5a6b256e62aafee41f89f1bfb8"
 | 
					      sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.0.6"
 | 
					    version: "2.1.0"
 | 
				
			||||||
  shared_preferences_windows:
 | 
					  shared_preferences_windows:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: shared_preferences_windows
 | 
					      name: shared_preferences_windows
 | 
				
			||||||
      sha256: "71bcd669bb9cdb6b39f22c4a7728b6d49e934f6cba73157ffa5a54f1eed67436"
 | 
					      sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.5"
 | 
					    version: "2.2.0"
 | 
				
			||||||
  sky_engine:
 | 
					  sky_engine:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description: flutter
 | 
					    description: flutter
 | 
				
			||||||
@@ -790,10 +790,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: webview_flutter_android
 | 
					      name: webview_flutter_android
 | 
				
			||||||
      sha256: "34f83c2f0f64c75ad75c77a2ccfc8d2e531afbe8ad41af1fd787d6d33336aa90"
 | 
					      sha256: "9e223788e1954087dac30d813dc151f8e12f09f1139f116ce20b5658893f3627"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "3.4.3"
 | 
					    version: "3.4.4"
 | 
				
			||||||
  webview_flutter_platform_interface:
 | 
					  webview_flutter_platform_interface:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -835,5 +835,5 @@ packages:
 | 
				
			|||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "6.2.2"
 | 
					    version: "6.2.2"
 | 
				
			||||||
sdks:
 | 
					sdks:
 | 
				
			||||||
  dart: ">=2.18.2 <3.0.0"
 | 
					  dart: ">=2.19.0 <3.0.0"
 | 
				
			||||||
  flutter: ">=3.4.0-17.0.pre"
 | 
					  flutter: ">=3.4.0-17.0.pre"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 | 
				
			|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
					# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
				
			||||||
# In Windows, build-name is used as the major, minor, and patch parts
 | 
					# In Windows, build-name is used as the major, minor, and patch parts
 | 
				
			||||||
# of the product and file versions while build-number is used as the build suffix.
 | 
					# of the product and file versions while build-number is used as the build suffix.
 | 
				
			||||||
version: 0.11.17+139 # When changing this, update the tag in main() accordingly
 | 
					version: 0.11.23+145 # When changing this, update the tag in main() accordingly
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
  sdk: '>=2.18.2 <3.0.0'
 | 
					  sdk: '>=2.18.2 <3.0.0'
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user