diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json deleted file mode 100644 index 367ed03..0000000 --- a/.dart_tool/package_config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "configVersion": 2, - "packages": [ - { - "name": "web_multiple_tab_detector", - "rootUri": "../", - "packageUri": "lib/", - "languageVersion": "2.12" - } - ], - "generated": "2022-02-16T08:12:09.964550Z", - "generator": "pub", - "generatorVersion": "2.16.1" -} diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml new file mode 100644 index 0000000..a3e84f8 --- /dev/null +++ b/.github/workflows/integrate.yml @@ -0,0 +1,27 @@ +name: Continious Integration + +on: + push: + branches: + - main + pull_request: + merge_group: + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + dart: + permissions: + contents: read + uses: famedly/frontend-ci-templates/.github/workflows/dart.yml@main + with: + env_file: ".github/workflows/versions.env" + secrets: + ssh_key: "${{ secrets.CI_SSH_PRIVATE_KEY }}" + + general: + permissions: + contents: read + uses: famedly/frontend-ci-templates/.github/workflows/general.yml@main diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 92a7abd..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Add issues to Product Management Project. - -on: - issues: - types: - - opened - -jobs: - add-to-project: - name: Add issue to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v0.5.0 - with: - # You can target a repository in a different organization - # to the issue - project-url: https://github.com/orgs/famedly/projects/4 - github-token: ${{ secrets.ADD_ISSUE_TO_PROJECT_PAT }} diff --git a/.github/workflows/versions.env b/.github/workflows/versions.env new file mode 100644 index 0000000..c65fc3a --- /dev/null +++ b/.github/workflows/versions.env @@ -0,0 +1 @@ +dart_version=3.10.4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 93d2a1e..2ded13c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .packages pubspec.lock +.dart_tool/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 688dab7..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,15 +0,0 @@ -image: - name: registry.gitlab.com/famedly/containers/flutter-dockerimages:stable - -variables: - GIT_SUBMODULE_STRATEGY: recursive - -stages: -- coverage -- publish - -code_analyze: - stage: coverage - script: - - flutter format lib/ --set-exit-if-changed - - flutter analyze diff --git a/example_app/.gitignore b/example_app/.gitignore new file mode 100644 index 0000000..3820a95 --- /dev/null +++ b/example_app/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example_app/.metadata b/example_app/.metadata new file mode 100644 index 0000000..6df09a2 --- /dev/null +++ b/example_app/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "84fc5cbb223bc12f83d65b647ff8a56caf779ffd" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: android + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: ios + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: linux + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: macos + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: web + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + - platform: windows + create_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + base_revision: 84fc5cbb223bc12f83d65b647ff8a56caf779ffd + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example_app/README.md b/example_app/README.md new file mode 100644 index 0000000..7df1962 --- /dev/null +++ b/example_app/README.md @@ -0,0 +1 @@ +# example_app diff --git a/example_app/analysis_options.yaml b/example_app/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/example_app/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example_app/lib/main.dart b/example_app/lib/main.dart new file mode 100644 index 0000000..9289043 --- /dev/null +++ b/example_app/lib/main.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:web_multiple_tab_detector/web_multiple_tab_detector.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + WebMultipleTabDetector.register(); + + var isOnlyTab = true; + + if (await WebMultipleTabDetector.isSingleTab()) { + debugPrint('First tab.'); + } else { + debugPrint('Second tab!!!'); + isOnlyTab = false; + } + runApp(MyApp(isOnlyTab: isOnlyTab)); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key, this.isOnlyTab = true}); + final bool isOnlyTab; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Web Multiple Tab Detector', + home: Home(isOnlyTab: isOnlyTab,), + ); + } +} + +class Home extends StatelessWidget { + const Home({super.key, this.isOnlyTab = true}); + final bool isOnlyTab; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Text( + isOnlyTab ? 'All Good =)!' : 'There is another tab!!!', + ), + ), + ); + } +} diff --git a/example_app/pubspec.yaml b/example_app/pubspec.yaml new file mode 100644 index 0000000..fd3bf19 --- /dev/null +++ b/example_app/pubspec.yaml @@ -0,0 +1,91 @@ +name: example_app +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# 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 +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.12.2 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.8 + web_multiple_tab_detector: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^6.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/example_app/web/favicon.png b/example_app/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/example_app/web/favicon.png differ diff --git a/example_app/web/icons/Icon-192.png b/example_app/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/example_app/web/icons/Icon-192.png differ diff --git a/example_app/web/icons/Icon-512.png b/example_app/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/example_app/web/icons/Icon-512.png differ diff --git a/example_app/web/icons/Icon-maskable-192.png b/example_app/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/example_app/web/icons/Icon-maskable-192.png differ diff --git a/example_app/web/icons/Icon-maskable-512.png b/example_app/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/example_app/web/icons/Icon-maskable-512.png differ diff --git a/example_app/web/index.html b/example_app/web/index.html new file mode 100644 index 0000000..ddb9218 --- /dev/null +++ b/example_app/web/index.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + example_app + + + + + + + diff --git a/example_app/web/manifest.json b/example_app/web/manifest.json new file mode 100644 index 0000000..16a251d --- /dev/null +++ b/example_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example_app", + "short_name": "example_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/lib/src/web.dart b/lib/src/web.dart index b92b033..a827fa2 100644 --- a/lib/src/web.dart +++ b/lib/src/web.dart @@ -16,9 +16,11 @@ * along with this program. If not, see . */ -import 'dart:html'; +import 'dart:js_interop'; import 'dart:math'; +import 'package:web/web.dart' as web; + String randomString([int length = 50]) { var result = ''; final chars = 'abcdefghijklmnopqrstuvwxyz-_1234567890='; @@ -32,7 +34,7 @@ String randomString([int length = 50]) { int getTabs(String name) { try { - final n = int.parse(window.localStorage[name]!); + final n = int.parse(web.window.localStorage.getItem(name)!); return n < 0 ? 0 : n; } catch (_) { return 0; @@ -40,7 +42,7 @@ int getTabs(String name) { } void setTabs(String name, int number) { - window.localStorage[name] = number.toString(); + web.window.localStorage.setItem(name, number.toString()); } bool _pongReceived = false; @@ -50,22 +52,26 @@ void register(String name) { _instanceId = randomString(); setTabs(name, getTabs(name) + 1); - window.onUnload.listen((_) { + void onUnloadCallback(web.Event event) { setTabs(name, getTabs(name) - 1); - }); + } + + web.window.onunload = onUnloadCallback.toJS; - window.onStorage.listen((evt) { + void onStorageCallback(web.StorageEvent evt) { if (evt.key == '$name-ping') { final val = evt.newValue!; if (val.split('|')[0] != _instanceId) { - window.localStorage['$name-pong'] = - _instanceId + '|' + DateTime.now().toString(); + web.window.localStorage.setItem( + '$name-pong', _instanceId + '|' + DateTime.now().toString()); } } if (evt.key == '$name-pong') { _pongReceived = true; } - }); + } + + web.window.onstorage = onStorageCallback.toJS; } Future isSingleTab(String name) async { @@ -74,8 +80,8 @@ Future isSingleTab(String name) async { return true; } // send ping to other tabs - window.localStorage['$name-ping'] = - _instanceId + '|' + DateTime.now().toString(); + web.window.localStorage + .setItem('$name-ping', _instanceId + '|' + DateTime.now().toString()); int counter = 100; while (!_pongReceived && counter > 0) { await Future.delayed(Duration(milliseconds: 50)); diff --git a/pubspec.yaml b/pubspec.yaml index 019d3d3..a406033 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,3 +6,7 @@ repository: https://gitlab.com/famedly/libraries/web_multiple_tab_detector environment: sdk: ">=2.12.0 <3.0.0" +dependencies: + web: ^1.1.1 +dev_dependencies: + import_sorter: ^4.6.0