diff --git a/.env.example b/.env.example index ad8dfa87..af1b481f 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,7 @@ POCKETBASE_URL= USERNAME= -PASSWORD= \ No newline at end of file +PASSWORD= + +# The format: +# SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2 +SPOTIFY_SECRETS= \ No newline at end of file diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 9ba2f497..e4b398bb 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -61,7 +61,7 @@ jobs: run: | flutter config --enable-windows-desktop flutter pub get - dart bin/create-secrets.dart '${{ secrets.LYRICS_SECRET }}' '${{ secrets.SPOTIFY_SECRET }}' + flutter pub run build_runner build --delete-conflicting-outputs - name: Build Windows Executable run: | @@ -99,7 +99,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update -y - sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev + sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev - name: Install AppImage Tool run: | @@ -136,7 +136,7 @@ jobs: run: | flutter config --enable-linux-desktop flutter pub get - dart bin/create-secrets.dart '${{ secrets.LYRICS_SECRET }}' '${{ secrets.SPOTIFY_SECRET }}' + flutter pub run build_runner build --delete-conflicting-outputs - name: Build Linux Packages run: | @@ -200,10 +200,10 @@ jobs: if: ${{ inputs.channel == 'nightly' }} run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - name: Generate Secrets and Build apk + - name: Generate Secrets run: | flutter pub get - dart bin/create-secrets.dart '${{ secrets.LYRICS_SECRET }}' '${{ secrets.SPOTIFY_SECRET }}' + flutter pub run build_runner build --delete-conflicting-outputs - name: Sign Apk run: | @@ -253,7 +253,7 @@ jobs: - name: Generate Secrets run: | flutter pub get - dart bin/create-secrets.dart '${{ secrets.LYRICS_SECRET }}' '${{ secrets.SPOTIFY_SECRET }}' + flutter pub run build_runner build --delete-conflicting-outputs - name: Build Macos App run: | diff --git a/.gitignore b/.gitignore index 1782ec11..96d81087 100644 --- a/.gitignore +++ b/.gitignore @@ -66,9 +66,8 @@ installer.exe # secrets *.env -lib/models/generated_secrets.dart +lib/collections/env.g.dart help.txt -secrets.json dist appimage-build @@ -76,4 +75,4 @@ appimage-build android/key.properties .fvm/flutter_sdk -**/pb_data \ No newline at end of file +**/pb_data diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index a32d58af..dc7518f9 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -120,38 +120,28 @@ Do the following: - Download the latest Flutter SDK (>=2.15.1) & enable desktop support - Install Development dependencies in linux - - `libappindicator3-1 gir1.2-appindicator3-0.1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev` (for Debian/Ubuntu) - - `libappindicator-gtk3 libsecret jsoncpp gstreamer gst-libav gst-plugins-base gst-plugins-good` (for Arch/Manjaro) - - `libappindicator libsecret libsecret-devel jsoncpp gstreamer1-devel gstreamer1-plugins-base-tools gstreamer1-doc gstreamer1-plugins-base-devel gstreamer1-plugins-good gstreamer1-plugins-good-extras` (for Fedora) -- Clone the Repo & Run `flutter pub get` in the Terminal -- Create a `secrets.json` in root of the project. The structure should be similar to the following example: - -```jsoc name="secrets.json" -{ - "LYRICS_SECRET": [ - "Bo3LQEMcL2xUAJ6yCfQowV6f8K78s9J9FLa67AsyWmvhkP9LWikkgcEyFrzvs7jsR", - "HiLHxLj8uv2VhBZfq9BQ9HVrWQk5Jc8aneMZX8RV4KjTmC387K692xrbNK35c8Qe4" - ], - "SPOTIFY_SECRET": [ - { - "clientId": "9ed19daf-c7a2-4c28-91ac-2c5283ad86cf", - "clientSecret": "236d5822-820e-457e-b18c-10e258c9386b" - }, - { - "clientId": "b4769027-e048-4485-8f0b-b8a336f2cd97", - "clientSecret": "41df6ea4-eba2-4d42-b7be-6f727555fccc" - } - ] -} -``` - -> You can add more clientId/clientSecret/genius-access-token if you want. The credentials used in the example are dummy (fake). You've to use your own secrets - + - Debian/Ubuntu + ```bash + $ apt-get install libappindicator3-1 gir1.2-appindicator3-0.1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev + ``` + - Use `libjsoncpp25` instead of `libjsoncpp1` (for Ubuntu >= 22.04) + - Arch/Manjaro + ```bash + yay -S libappindicator-gtk3 libsecret jsoncpp gstreamer gst-libav gst-plugins-base gst-plugins-good + ``` + - Fedora + ```bash + dnf install libappindicator libsecret libsecret-devel jsoncpp gstreamer1-devel gstreamer1-plugins-base-tools gstreamer1-doc gstreamer1-plugins-base-devel gstreamer1-plugins-good gstreamer1-plugins-good-extras + ``` +- Clone the Repo +- Create a `.env` in root of the project following the `.env.example` template +- Now run the following to bootstrap the project + ```bash + flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs + ``` - Finally run these following commands in the root of the project to start the Spotube Locally - -```bash -$ dart bin/create-secrets.dart --local -$ flutter run -d )> -``` + ```bash + flutter run -d )> + ``` Do debugging/testing/build etc then submit to us with PR against the development branch (master) & we'll review your code diff --git a/android/app/src/main/res/drawable/ic_launcher_monochrome.xml b/android/app/src/main/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 00000000..8aae0e6c --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 5f349f7f..f606c4d8 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ + diff --git a/bin/create-secrets.dart b/bin/create-secrets.dart deleted file mode 100644 index e59c5668..00000000 --- a/bin/create-secrets.dart +++ /dev/null @@ -1,177 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:path/path.dart' as path; - -// blob metadata for de-stringifying -const randHash = [ - 49, - 111, - 98, - 72, - 78, - 122, - 98, - 48, - 112, - 73, - 81, - 50, - 112, - 89, - 90, - 50, - 116, - 83, - 84, - 110, - 99, - 105, - 76, - 67, - 74, - 67, - 89, - 121, - 48, - 119, - 77, - 106, - 69, - 50, - 86, - 69, - 53, - 107, - 77, - 69, - 86, - 71, - 101, - 68, - 66, - 113, - 78, - 110, - 66, - 119 -]; -const sugarCarbonator = [ - 81, - 119, - 79, - 71, - 85, - 53, - 78, - 50, - 69, - 52, - 90, - 68, - 107, - 120, - 77, - 87, - 89, - 52, - 89, - 84, - 73 -]; -const randomSalt = [ - 70, - 117, - 67, - 75, - 117, - 116, - 72, - 101, - 105, - 102, - 65, - 110, - 68, - 87, - 72, - 97, - 84, - 85, - 82, - 100, - 79, - 73, - 110, - 103, - 83, - 117, - 75, - 115 -]; -const algorithmicSugar = [ - 70, - 117, - 67, - 75, - 117, - 116, - 72, - 101, - 105, - 102, - 65, - 78, - 100, - 102, - 68, - 114, - 79, - 105, - 100, - 115, - 85, - 99, - 107, - 83 -]; - -void main(List args) async { - List val; - List val2; - - final cwd = Directory.current.path; - final binSafe = cwd.endsWith("/bin") ? ".." : ""; - if (args.isEmpty) { - throw ArgumentError("Expected 1-3 arguments but passed none"); - } - if (args.contains("--local")) { - final secretFilePath = path.join(cwd, binSafe, "secrets.json"); - final file = File(secretFilePath); - if (!file.existsSync()) throw Exception("secrets.json file not found"); - final data = jsonDecode(await file.readAsString()); - val = List.castFrom(data["LYRICS_SECRET"]); - val2 = List.castFrom(data["SPOTIFY_SECRET"]); - } else if (args.contains("--fdroid")) { - final decodedLyricSecret = utf8.decode(base64Decode( - args[1].replaceAll( - String.fromCharCodes(randomSalt), String.fromCharCodes(randHash)), - )); - final decodedSpotifySecret = utf8.decode(base64Decode( - args.last.replaceAll(String.fromCharCodes(algorithmicSugar), - String.fromCharCodes(sugarCarbonator)), - )); - val = List.castFrom(jsonDecode(decodedLyricSecret)); - val2 = List.castFrom(jsonDecode(decodedSpotifySecret)); - } else { - final decodedLyricSecret = utf8.decode(base64Decode(args.first)); - final decodedSpotifySecret = utf8.decode(base64Decode(args.last)); - val = List.castFrom(jsonDecode(decodedLyricSecret)); - val2 = List.castFrom(jsonDecode(decodedSpotifySecret)); - } - - await File(path.join(cwd, binSafe, "lib/models/generated_secrets.dart")) - .writeAsString( - "final List lyricsSecrets = ${jsonEncode(val)};\nfinal List> spotifySecrets = ${jsonEncode(val2)};", - ); -} diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index b6b97cdf..80c82050 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -5,11 +5,9 @@ // coverage:ignore-file // ignore_for_file: type=lint -// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use import 'package:flutter/widgets.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:flutter/services.dart'; class $AssetsTutorialGen { const $AssetsTutorialGen(); @@ -39,8 +37,7 @@ class Assets { AssetGenImage('assets/spotube-logo-foreground.jpg'); static const AssetGenImage spotubeLogoPng = AssetGenImage('assets/spotube-logo.png'); - static const SvgGenImage spotubeLogoSvg = - SvgGenImage('assets/spotube-logo.svg'); + static const String spotubeLogoSvg = 'assets/spotube-logo.svg'; static const AssetGenImage spotubeScreenshot = AssetGenImage('assets/spotube-screenshot.jpg'); static const AssetGenImage spotubeBanner = @@ -129,54 +126,3 @@ class AssetGenImage { String get keyName => _assetName; } - -class SvgGenImage { - const SvgGenImage(this._assetName); - - final String _assetName; - - SvgPicture svg({ - Key? key, - bool matchTextDirection = false, - AssetBundle? bundle, - String? package, - double? width, - double? height, - BoxFit fit = BoxFit.contain, - AlignmentGeometry alignment = Alignment.center, - bool allowDrawingOutsideViewBox = false, - WidgetBuilder? placeholderBuilder, - Color? color, - BlendMode colorBlendMode = BlendMode.srcIn, - String? semanticsLabel, - bool excludeFromSemantics = false, - Clip clipBehavior = Clip.hardEdge, - bool cacheColorFilter = false, - SvgTheme? theme, - }) { - return SvgPicture.asset( - _assetName, - key: key, - matchTextDirection: matchTextDirection, - bundle: bundle, - package: package, - width: width, - height: height, - fit: fit, - alignment: alignment, - allowDrawingOutsideViewBox: allowDrawingOutsideViewBox, - placeholderBuilder: placeholderBuilder, - color: color, - colorBlendMode: colorBlendMode, - semanticsLabel: semanticsLabel, - excludeFromSemantics: excludeFromSemantics, - clipBehavior: clipBehavior, - cacheColorFilter: cacheColorFilter, - theme: theme, - ); - } - - String get path => _assetName; - - String get keyName => _assetName; -} diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 7921c684..8748d921 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -1,17 +1,24 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:envied/envied.dart'; +part 'env.g.dart'; + +@Envied(obfuscate: true, requireEnvFile: true, path: ".env") abstract class Env { - static final String pocketbaseUrl = - dotenv.get('POCKETBASE_URL', fallback: 'http://127.0.0.1:8090'); - static final String username = dotenv.get('USERNAME', fallback: 'root'); - static final String password = dotenv.get('PASSWORD', fallback: '12345678'); + @EnviedField(varName: 'POCKETBASE_URL', defaultValue: 'http://127.0.0.1:8090') + static final pocketbaseUrl = _Env.pocketbaseUrl; - static configure() async { - if (kReleaseMode) { - await dotenv.load(fileName: ".env"); - } else { - dotenv.testLoad(); - } - } + @EnviedField(varName: 'USERNAME', defaultValue: 'root') + static final username = _Env.username; + + @EnviedField(varName: 'PASSWORD', defaultValue: '12345678') + static final password = _Env.password; + + @EnviedField(varName: 'SPOTIFY_SECRETS') + static final spotifySecrets = _Env.spotifySecrets.split(',').map((e) { + final secrets = e.trim().split(":").map((e) => e.trim()); + return { + "clientId": secrets.first, + "clientSecret": secrets.last, + }; + }).toList(); } diff --git a/lib/main.dart b/lib/main.dart index 71688d49..9bf71b9c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:metadata_god/metadata_god.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:spotube/collections/env.dart'; import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/entities/cache_track.dart'; import 'package:spotube/collections/routes.dart'; @@ -87,7 +86,6 @@ Future main(List rawArgs) async { Hive.registerAdapter(CacheTrackAdapter()); Hive.registerAdapter(CacheTrackEngagementAdapter()); Hive.registerAdapter(CacheTrackSkipSegmentAdapter()); - await Env.configure(); Catcher( enableLogger: arguments["verbose"], diff --git a/lib/provider/spotify_provider.dart b/lib/provider/spotify_provider.dart index cd557c39..2675a9f7 100644 --- a/lib/provider/spotify_provider.dart +++ b/lib/provider/spotify_provider.dart @@ -1,12 +1,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/models/generated_secrets.dart'; +import 'package:spotube/collections/env.dart'; + import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/utils/primitive_utils.dart'; final spotifyProvider = Provider((ref) { final authState = ref.watch(AuthenticationNotifier.provider); - final anonCred = PrimitiveUtils.getRandomElement(spotifySecrets); + final anonCred = PrimitiveUtils.getRandomElement(Env.spotifySecrets); if (authState == null) { return SpotifyApi( diff --git a/lib/provider/user_preferences_provider.dart b/lib/provider/user_preferences_provider.dart index 43250660..b1e2dcac 100644 --- a/lib/provider/user_preferences_provider.dart +++ b/lib/provider/user_preferences_provider.dart @@ -4,10 +4,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/models/generated_secrets.dart'; + import 'package:spotube/utils/persisted_change_notifier.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/primitive_utils.dart'; import 'package:path/path.dart' as path; enum LayoutMode { @@ -30,7 +29,6 @@ class UserPreferences extends PersistedChangeNotifier { ThemeMode themeMode; String recommendationMarket; bool saveTrackLyrics; - String geniusAccessToken; bool checkUpdate; AudioQuality audioQuality; @@ -48,7 +46,6 @@ class UserPreferences extends PersistedChangeNotifier { bool showSystemTrayIcon; UserPreferences({ - required this.geniusAccessToken, required this.recommendationMarket, required this.themeMode, required this.layoutMode, @@ -95,12 +92,6 @@ class UserPreferences extends PersistedChangeNotifier { updatePersistence(); } - void setGeniusAccessToken(String token) { - geniusAccessToken = token; - notifyListeners(); - updatePersistence(); - } - void setAccentColorScheme(SpotubeColor color) { accentColorScheme = color; notifyListeners(); @@ -172,8 +163,6 @@ class UserPreferences extends PersistedChangeNotifier { saveTrackLyrics = map["saveTrackLyrics"] ?? false; recommendationMarket = map["recommendationMarket"] ?? recommendationMarket; checkUpdate = map["checkUpdate"] ?? checkUpdate; - geniusAccessToken = map["geniusAccessToken"] ?? - PrimitiveUtils.getRandomElement(lyricsSecrets); themeMode = ThemeMode.values[map["themeMode"] ?? 0]; accentColorScheme = map["accentColorScheme"] != null @@ -205,7 +194,6 @@ class UserPreferences extends PersistedChangeNotifier { return { "saveTrackLyrics": saveTrackLyrics, "recommendationMarket": recommendationMarket, - "geniusAccessToken": geniusAccessToken, "themeMode": themeMode.index, "accentColorScheme": accentColorScheme.toString(), "checkUpdate": checkUpdate, @@ -223,7 +211,6 @@ class UserPreferences extends PersistedChangeNotifier { final userPreferencesProvider = ChangeNotifierProvider( (_) => UserPreferences( accentColorScheme: SpotubeColor(Colors.blue.value, name: "Blue"), - geniusAccessToken: "", recommendationMarket: 'US', themeMode: ThemeMode.system, layoutMode: kIsMobile ? LayoutMode.compact : LayoutMode.adaptive, diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 9264f535..c1ad94c7 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -9,7 +9,7 @@ import 'package:spotube/models/logger.dart'; import 'package:http/http.dart' as http; import 'package:spotube/models/lyrics.dart'; import 'package:spotube/models/spotube_track.dart'; -import 'package:spotube/models/generated_secrets.dart'; + import 'package:spotube/utils/primitive_utils.dart'; import 'package:collection/collection.dart'; import 'package:html/parser.dart' as parser; @@ -23,6 +23,7 @@ abstract class ServiceUtils { .trim(); } + @Deprecated("In favor spotify lyrics api, this isn't needed anymore") static String getTitle( String title, { List artists = const [], @@ -77,6 +78,7 @@ abstract class ServiceUtils { return lyrics; } + @Deprecated("In favor spotify lyrics api, this isn't needed anymore") static Future searchSong( String title, List artist, { @@ -85,7 +87,7 @@ abstract class ServiceUtils { bool authHeader = false, }) async { if (apiKey == "" || apiKey == null) { - apiKey = PrimitiveUtils.getRandomElement(lyricsSecrets); + apiKey = PrimitiveUtils.getRandomElement(/* lyricsSecrets */ []); } const searchUrl = 'https://api.genius.com/search?q='; String song = @@ -111,6 +113,7 @@ abstract class ServiceUtils { return results; } + @Deprecated("In favor spotify lyrics api, this isn't needed anymore") static Future getLyrics( String title, List artists, { @@ -158,8 +161,10 @@ abstract class ServiceUtils { return lyrics; } + @Deprecated("In favor spotify lyrics api, this isn't needed anymore") static const baseUri = "https://www.rentanadviser.com/subtitles"; + @Deprecated("In favor spotify lyrics api, this isn't needed anymore") static Future getTimedLyrics(SpotubeTrack track) async { final artistNames = track.artists?.map((artist) => artist.name!).toList() ?? []; diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml index e6ad8c61..80e6d65a 100644 --- a/linux/packaging/deb/make_config.yaml +++ b/linux/packaging/deb/make_config.yaml @@ -15,7 +15,6 @@ dependencies: - libappindicator3-1 - gir1.2-appindicator3-0.1 - libsecret-1-0 - - libjsoncpp1 essential: false icon: assets/spotube-logo.png diff --git a/pubspec.lock b/pubspec.lock index 7cb82a3d..a02cc969 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -506,6 +506,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + envied: + dependency: "direct main" + description: + name: envied + sha256: d5d978fbd578b5c00123003609c39185e0b1ddf9d2ac460d710dd0eb2fc223d7 + url: "https://pub.dev" + source: hosted + version: "0.3.0" + envied_generator: + dependency: "direct dev" + description: + name: envied_generator + sha256: "6c5a98c27c5eae925807692eb252ccac2b8e81f09bace1f07207c47dfb6a4eb0" + url: "https://pub.dev" + source: hosted + version: "0.3.0" fake_async: dependency: transitive description: @@ -624,14 +640,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2" - flutter_dotenv: - dependency: "direct main" - description: - name: flutter_dotenv - sha256: d9283d92059a22e9834bc0a31336658ffba77089fb6f3cc36751f1fc7c6661a3 - url: "https://pub.dev" - source: hosted - version: "5.0.2" flutter_driver: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 621ca32d..d9013ecd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: cupertino_icons: ^1.0.5 curved_navigation_bar: ^1.0.3 dbus: ^0.7.8 + envied: ^0.3.0 file_picker: ^5.2.2 fl_query: ^1.0.0-alpha.2 fl_query_hooks: ^1.0.0-alpha.2 @@ -32,7 +33,6 @@ dependencies: flutter: sdk: flutter flutter_cache_manager: ^3.3.0 - flutter_dotenv: ^5.0.2 flutter_feather_icons: ^2.0.0+1 flutter_hooks: ^0.18.2+1 flutter_inappwebview: ^5.7.2+3 @@ -92,6 +92,7 @@ dependencies: dev_dependencies: build_runner: ^2.3.2 + envied_generator: ^0.3.0 flutter_distributor: ^0.0.2 flutter_gen_runner: ^5.1.0+1 flutter_launcher_icons: ^0.11.0 @@ -112,7 +113,6 @@ flutter: assets: - assets/ - assets/tutorial/ - - .env - LICENSE flutter_icons: @@ -130,5 +130,3 @@ flutter_icons: flutter_gen: output: lib/collections - integrations: - flutter_svg: true