diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml
new file mode 100644
index 0000000..b8ed782
--- /dev/null
+++ b/.idea/libraries/Dart_Packages.xml
@@ -0,0 +1,444 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml
index 008f0f6..6ae284f 100644
--- a/.idea/libraries/Dart_SDK.xml
+++ b/.idea/libraries/Dart_SDK.xml
@@ -1,25 +1,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sources/dafl_project_flutter/.metadata b/Sources/dafl_project_flutter/.metadata
index e1179a6..308a9a8 100644
--- a/Sources/dafl_project_flutter/.metadata
+++ b/Sources/dafl_project_flutter/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled.
version:
- revision: 18a827f3933c19f51862dde3fa472197683249d6
+ revision: eb6d86ee27deecba4a83536aa20f366a6044895c
channel: stable
project_type: app
@@ -13,26 +13,14 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
+ create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
+ base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
- platform: android
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
+ create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
+ base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
- platform: ios
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
- - platform: linux
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
- - platform: macos
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
- - platform: web
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
- - platform: windows
- create_revision: 18a827f3933c19f51862dde3fa472197683249d6
- base_revision: 18a827f3933c19f51862dde3fa472197683249d6
+ create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
+ base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
# User provided section
diff --git a/Sources/dafl_project_flutter/android/app/build.gradle b/Sources/dafl_project_flutter/android/app/build.gradle
index fce04cc..97360f6 100644
--- a/Sources/dafl_project_flutter/android/app/build.gradle
+++ b/Sources/dafl_project_flutter/android/app/build.gradle
@@ -47,7 +47,8 @@ android {
applicationId "com.example.dafl_project_flutter"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
- minSdkVersion flutter.minSdkVersion
+ //minSdkVersion flutter.minSdkVersion
+ minSdkVersion 17
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/Sources/dafl_project_flutter/android/app/src/main/AndroidManifest.xml b/Sources/dafl_project_flutter/android/app/src/main/AndroidManifest.xml
index ed40f7f..defab80 100644
--- a/Sources/dafl_project_flutter/android/app/src/main/AndroidManifest.xml
+++ b/Sources/dafl_project_flutter/android/app/src/main/AndroidManifest.xml
@@ -3,7 +3,7 @@
+
+
-
+
+
+
diff --git a/Sources/dafl_project_flutter/android/build.gradle b/Sources/dafl_project_flutter/android/build.gradle
index 83ae220..4256f91 100644
--- a/Sources/dafl_project_flutter/android/build.gradle
+++ b/Sources/dafl_project_flutter/android/build.gradle
@@ -6,7 +6,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.1.2'
+ classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/Sources/dafl_project_flutter/android/gradle/wrapper/gradle-wrapper.properties b/Sources/dafl_project_flutter/android/gradle/wrapper/gradle-wrapper.properties
index cb24abd..3c9d085 100644
--- a/Sources/dafl_project_flutter/android/gradle/wrapper/gradle-wrapper.properties
+++ b/Sources/dafl_project_flutter/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
diff --git a/Sources/dafl_project_flutter/ios/Runner/Info.plist b/Sources/dafl_project_flutter/ios/Runner/Info.plist
index 60521b9..fdf519a 100644
--- a/Sources/dafl_project_flutter/ios/Runner/Info.plist
+++ b/Sources/dafl_project_flutter/ios/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- dafl_project_flutter
+ Dafl Music
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/Sources/dafl_project_flutter/lib/spotify_api/.gitkeep b/Sources/dafl_project_flutter/lib/api/.gitkeep
similarity index 100%
rename from Sources/dafl_project_flutter/lib/spotify_api/.gitkeep
rename to Sources/dafl_project_flutter/lib/api/.gitkeep
diff --git a/Sources/dafl_project_flutter/lib/api/api.dart b/Sources/dafl_project_flutter/lib/api/api.dart
new file mode 100644
index 0000000..982282c
--- /dev/null
+++ b/Sources/dafl_project_flutter/lib/api/api.dart
@@ -0,0 +1,156 @@
+import 'dart:convert';
+import 'dart:math';
+import 'package:http/http.dart' as http;
+import 'package:crypto/crypto.dart';
+
+import 'track.dart';
+
+class Api {
+ //from dashboard
+ final _clientId = '7ceb49d874b9404492246027e4d68cf8';
+ final _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
+
+ //for web api
+ get redirectUri => 'https://daflmusic.000webhostapp.com/callback/';
+ final _scopes = 'user-read-playback-state user-read-currently-playing';
+ late String _state;
+ dynamic _codeVerifier;
+ dynamic _codeChallenge;
+ late String _encodedLogs;
+ final _tokenType = 'Bearer ';
+
+ //from web api
+ String? _code;
+ int? _expiresIn;
+ String? _refreshToken;
+ String? _accessToken; //use _getToken() as kind of a private getter
+
+ //other
+ final _client = http.Client();
+ late Uri _urlAuthorize;
+
+ get urlAuthorize => _urlAuthorize;
+ DateTime? _tokenEnd;
+
+ Api() {
+ _state = _generateRandomString(16);
+ _codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
+ _codeChallenge = _generateCodeChallenge();
+ print(_codeChallenge);
+ _encodedLogs = base64.encode(utf8.encode("$_clientId:$_clientSecret"));
+ _urlAuthorize = Uri.https('accounts.spotify.com', 'authorize', {
+ 'client_id': _clientId,
+ 'response_type': 'code',
+ 'redirect_uri': redirectUri,
+ 'state': _state,
+ 'scope': _scopes,
+ 'show_dialog': 'false',
+ 'code_challenge_method': 'S256',
+ 'code_challenge': _codeChallenge
+ });
+ }
+
+ //PKCE generations
+
+ _generateRandomInt(int min, int max) {
+ return min + Random().nextInt(max - min);
+ }
+
+ _generateRandomString(int length) {
+ const chars =
+ 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
+ return String.fromCharCodes(Iterable.generate(
+ length, (_) => chars.codeUnitAt(Random().nextInt(chars.length))));
+ }
+
+ _generateCodeChallenge() {
+ //care : base64Url doesn't work
+ return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
+ .replaceAll('+', '-')
+ .replaceAll('/', '_')
+ .replaceAll('=', '');
+ }
+
+ //session management
+
+ requestUserAuthorization(Uri url) async {
+ if (url.queryParameters['state'] == _state.toString()) {
+ _code = url.queryParameters['code'];
+ await _requestAccessToken();
+ }
+ // TODO : implement the else
+ }
+
+ _requestAccessToken() async {
+ var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
+ 'code': _code,
+ 'redirect_uri': redirectUri,
+ 'grant_type': 'authorization_code',
+ 'client_id': _clientId,
+ 'code_verifier': _codeVerifier
+ });
+ var response = await _client.post(urlToken, headers: {
+ 'Authorization': 'Basic $_encodedLogs',
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ });
+ var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
+ _accessToken = decodedResponse['access_token'];
+ _expiresIn = decodedResponse['expires_in'];
+ _tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
+ _refreshToken = decodedResponse['refresh_token'];
+ }
+
+ Future _getToken() async {
+ await _tokenValidity();
+ return _accessToken;
+ }
+
+ _tokenValidity() async {
+ if (DateTime.now().isAfter(_tokenEnd!)) {
+ await _getRefreshedAccessToken();
+ }
+ }
+
+ _getRefreshedAccessToken() async {
+ var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
+ 'grant_type': 'refresh_token',
+ 'refresh_token': _refreshToken,
+ 'client_id': _clientId
+ });
+ var response = await _client.post(urlToken, headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ });
+ var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
+ _accessToken = decodedResponse['access_token'];
+ _expiresIn = decodedResponse['expires_in'];
+ _tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
+ }
+
+ //functional methods
+
+ Future getCurrentlyPlayingTrack() async {
+ var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
+ var token = await _getToken();
+ var response = await _client.get(url, headers: {
+ 'Authorization': '$_tokenType $token',
+ 'Content-Type': 'application/json'
+ });
+ var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
+ return decodedResponse['item']['id'];
+ }
+
+ Future