Skip to content

Commit

Permalink
Merge pull request #10 from C0ntrolDev/dev-1.1
Browse files Browse the repository at this point in the history
Ver 1.1.1
  • Loading branch information
C0ntrolDev authored Aug 17, 2024
2 parents d50c90b + f4bcce2 commit b100113
Show file tree
Hide file tree
Showing 66 changed files with 1,049 additions and 678 deletions.
25 changes: 5 additions & 20 deletions .metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.

version:
revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e"
revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
channel: "stable"

project_type: app
Expand All @@ -13,26 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
- platform: android
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: ios
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: linux
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: macos
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: web
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: windows
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49

# User provided section

Expand Down
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ App that allows you to download your favorite playlists at the touch of just one
### Android

You can download this apk if you don't know what kind of architecture you have.
- [spotify_downloader.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.0/spotify_downloader.apk)
- [spotify_downloader.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.1/spotify_downloader.apk)

If you know what architecture you have, then download one of the apk listed below.
- [spotify_downloader_armeabi-v7a.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.0/spotify_downloader_armeabi-v7a.apk)
- [spotify_downloader_arm64-v8a.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.0/spotify_downloader_arm64-v8a.apk)
- [spotify_downloader_x86_64.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.0/spotify_downloader_x86_64.apk)
- [spotify_downloader_armeabi-v7a.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.1/spotify_downloader_armeabi-v7a.apk)
- [spotify_downloader_arm64-v8a.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.1/spotify_downloader_arm64-v8a.apk)
- [spotify_downloader_x86_64.apk](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.1/spotify_downloader_x86_64.apk)

### IOS

You can download ipa there.
- [spotify_downloader.ipa](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.0/spotify_downloader.ipa)
- [spotify_downloader.ipa](https://github.com/C0ntrolDev/spotify_downloader/releases/download/v1.1.1/spotify_downloader.ipa)

## How to use

After you have downloaded the application, you must grant it the permissions it will ask for.
After you have downloaded the app, you must grant it the permissions it will ask for.
Then you can use the app. Just paste the link to the playlist and click the search button.

If you want to download your favorite tracks, and also download playlists "only for you", you must create Spotify Service App
Expand Down Expand Up @@ -73,6 +73,15 @@ __After logging in, you can download your favorite tracks, as well as playlists
1. Developed on Flutter
2. When developing the application, I used a "Clean Architecture". I don't think this application is an ideal representative of this approach. But if you want, you can use it as an example project.

### Version 2.0

If you're interested in contributing to this project, there are some key tasks I'd like to get done:

- [ ] Implement logging (probably using [talker](https://github.com/Frezyx/talker))
- [ ] Implement caching for the most recently loaded pages
- [ ] Remake the system for getting tracks from SpotifyAPI (make it so that the collection is fetched in parts, prioritizing loading parts that are visible)
- [ ] Implement various sources of tracks/audio

<h3 align="center">
^_^
</h3>
</h3>
1 change: 1 addition & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'NO'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.notification
Expand Down
10 changes: 6 additions & 4 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@
BAAF9E8CA93412EEA29D2F87 /* Pods-RunnerTests.release.xcconfig */,
20C59286EA4762C02DB57A1E /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand Down Expand Up @@ -467,6 +466,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 642R69GYA2;
Expand All @@ -476,7 +476,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.c0dev.spotifyDownloader;
PRODUCT_BUNDLE_IDENTIFIER = com.cdev.spotifyDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -646,6 +646,7 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 642R69GYA2;
Expand All @@ -655,7 +656,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.c0dev.spotifyDownloader;
PRODUCT_BUNDLE_IDENTIFIER = com.cdev.spotifyDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand All @@ -669,6 +670,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 642R69GYA2;
Expand All @@ -678,7 +680,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.c0dev.spotifyDownloader;
PRODUCT_BUNDLE_IDENTIFIER = com.cdev.spotifyDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand Down
2 changes: 1 addition & 1 deletion lib/core/app/colors/colors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const errorPrimaryColor = Color.fromARGB(255, 255, 102, 91);
const searchFieldColor = Color.fromARGB(255, 255, 255, 255);
const searchFieldHintColor = Color.fromARGB(255, 59, 59, 59);

const dialogColor = Color.fromARGB(255, 59, 59, 59);
const dialogColor = Color.fromARGB(255, 30, 30, 30);

const tilePlaceholderColor = Color.fromARGB(255, 59, 59, 59);

Expand Down
36 changes: 19 additions & 17 deletions lib/core/app/spotify_downloader_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:spotify_downloader/core/app/router/router.dart';
import 'package:spotify_downloader/core/app/themes/themes.dart';
import 'package:spotify_downloader/core/package_info/package_info_accessor.dart';
import 'package:spotify_downloader/core/accessors/package_info/package_info_accessor.dart';
import 'package:spotify_downloader/generated/l10n.dart';

class SpotifyDownloaderApp extends StatefulWidget {
Expand All @@ -23,6 +23,7 @@ class SpotifyDownloaderApp extends StatefulWidget {
}

class _SpotifyDownloaderAppState extends State<SpotifyDownloaderApp> {
final navigatorKey = GlobalKey();
final _appRouter = AppRouter();
String _language = 'en';

Expand All @@ -33,28 +34,28 @@ class _SpotifyDownloaderAppState extends State<SpotifyDownloaderApp> {
if (widget.locale != null) {
_language = widget.locale!;
}

initTheme();
}

@override
Widget build(BuildContext context) {
return MaterialApp.router(
locale: Locale(_language),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
routerConfig: _appRouter.config(navigatorObservers: () => [AutoRouteObserver()]),
theme: mainTheme,
builder: (context, child) {
return ScrollConfiguration(
behavior: const ClampingScrollPhysicsBehavior().copyWith(overscroll: false),
child: PackageInfoAccessor(packageInfo: widget.packageInfo, child: child!));
},
);
locale: Locale(_language),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
routerConfig: _appRouter.config(navigatorObservers: () => [AutoRouteObserver()]),
theme: mainTheme,
builder: (context, child) {
return ScrollConfiguration(
behavior: const ClampingScrollPhysicsBehavior().copyWith(overscroll: false),
child: PackageInfoAccessor(packageInfo: widget.packageInfo, child: child!));
});
}

changeLanguage(String language) {
Expand All @@ -63,3 +64,4 @@ class _SpotifyDownloaderAppState extends State<SpotifyDownloaderApp> {
});
}
}

31 changes: 0 additions & 31 deletions lib/core/app/themes/themes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,37 +87,6 @@ void initTheme() {
systemNavigationBarColor: Colors.transparent,
),
);
}

void showBigTextSnackBar(String message, BuildContext context, [Duration duration = const Duration(seconds: 2)]) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Column(
children: [
Text(
message,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(overflow: TextOverflow.visible),
),
],
),
duration: duration,
));
}

void showSmallTextSnackBar(String message, BuildContext context, [Duration duration = const Duration(seconds: 2)]) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))),
content: Column(
children: [
Text(
message,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelMedium?.copyWith(overflow: TextOverflow.visible),
),
],
),
duration: duration,
));
}

class TransitionsBuildersExtension {
Expand Down
5 changes: 3 additions & 2 deletions lib/core/di/injector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import 'package:spotify_downloader/features/data_domain/auth/network_auth/networ
import 'package:spotify_downloader/features/data_domain/auth/service/service.dart';
import 'package:spotify_downloader/features/data_domain/settings/settings.dart';
import 'package:spotify_downloader/features/data_domain/spotify_profile/spotify_profile.dart';
import 'package:spotify_downloader/features/data_domain/tracks/download_tracks/data/data_sources/tools/audio_metadata_editor/audio_metadata_editor_impl.dart';
import 'package:spotify_downloader/features/data_domain/tracks/download_tracks/data/data_sources/tools/audio_metadata_editor/metadata_god_audio_metadata_editor_impl.dart';
import 'package:spotify_downloader/features/data_domain/tracks/download_tracks/data/data_sources/tools/bitrate_editor/low_level_bitrate_editor_impl.dart';
import 'package:spotify_downloader/features/data_domain/tracks/download_tracks/data/data_sources/tools/file_to_mp3_converter/ffmpeg_file_to_mp3_converter.dart';
import 'package:spotify_downloader/features/data_domain/tracks/download_tracks/download_tracks.dart';
import 'package:spotify_downloader/features/data_domain/tracks/local_tracks/local_tracks.dart';
Expand Down Expand Up @@ -64,7 +65,7 @@ Future<void> _provideDataSources() async {
TracksCollectonsHistoryDataSource(localDb: injector.get<LocalDb>()));
injector.registerSingleton<NetworkTracksCollectionsDataSource>(NetworkTracksCollectionsDataSource());
injector.registerSingleton<DownloadAudioFromYoutubeDataSource>(DownloadAudioFromYoutubeDataSource(
audioMetadataEditor: AudioMetadataEditorImpl(), fileToMp3Converter: FFmpegFileToMp3Converter()));
audioMetadataEditor: MetadataGodAudioMetadataEditorImpl(), fileToMp3Converter: FFmpegFileToMp3Converter(), audioBitrateEditor: LowLevelMp3AudioBitrateEditorImpl()));
await injector.get<DownloadAudioFromYoutubeDataSource>().init();
injector.registerSingleton<NetworkTracksDataSource>(NetworkTracksDataSource());
await injector.get<NetworkTracksDataSource>().init();
Expand Down
44 changes: 27 additions & 17 deletions lib/core/utils/failures/custom_failures.dart
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
import 'package:spotify_downloader/core/utils/failures/failure.dart';

final class NotFoundFailure extends Failure {
const NotFoundFailure({super.message = 'not found failure'});
abstract class NoDetailedFailure extends Failure {
const NoDetailedFailure({required super.message, super.stackTrace});

@override
String toString() {
final type = runtimeType;
return '$type: $message';
}
}

final class NetworkFailure extends Failure {
const NetworkFailure({super.message = 'network failure'});
final class NotFoundFailure extends NoDetailedFailure {
const NotFoundFailure({super.message = 'not found failure', super.stackTrace});
}

final class ConverterFailure extends Failure {
const ConverterFailure({super.message = 'converter failure'});
final class NetworkFailure extends NoDetailedFailure {
const NetworkFailure({super.message = 'network failure', super.stackTrace});
}

final class AuthFailure extends Failure {
AuthFailure({super.message = 'auth failure'});
final class ConverterFailure extends NoDetailedFailure {
const ConverterFailure({super.message = 'converter failure', super.stackTrace});
}

final class InvalidClientCredentialsFailure extends Failure {
InvalidClientCredentialsFailure({super.message = 'invalid auth credentials failure'});
final class AuthFailure extends NoDetailedFailure {
AuthFailure({super.message = 'auth failure', super.stackTrace});
}

final class InvalidAccountCredentialsFailure extends Failure {
InvalidAccountCredentialsFailure({super.message = 'invalid refresh token failure'});
final class InvalidClientCredentialsFailure extends NoDetailedFailure {
InvalidClientCredentialsFailure({super.message = 'invalid auth credentials failure', super.stackTrace});
}

final class NotAuthorizedFailure extends Failure {
NotAuthorizedFailure({super.message = 'User not authorized'});
final class InvalidAccountCredentialsFailure extends NoDetailedFailure {
InvalidAccountCredentialsFailure({super.message = 'invalid refresh token failure', super.stackTrace});
}

final class ForbiddenFailure extends Failure {
ForbiddenFailure({super.message = 'Access Forbidden'});
}
final class NotAuthorizedFailure extends NoDetailedFailure {
NotAuthorizedFailure({super.message = 'User not authorized', super.stackTrace});
}

final class ForbiddenFailure extends NoDetailedFailure {
ForbiddenFailure({super.message = 'Access Forbidden', super.stackTrace});
}
9 changes: 7 additions & 2 deletions lib/core/utils/failures/failure.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
class Failure {
const Failure({required this.message});
const Failure({required this.message, this.stackTrace});

final Object? stackTrace;
final Object message;

@override
String toString() {
return toDetailedString();
}

String toDetailedString() {
final type = runtimeType;
return '$type: $message';
return '$type: "$stackTrace" $message';
}
}
Loading

0 comments on commit b100113

Please sign in to comment.