diff --git a/Sources/dafl_project_flutter/lib/api/api.dart b/Sources/dafl_project_flutter/lib/api/api.dart index 11b360a..c41ef3d 100644 --- a/Sources/dafl_project_flutter/lib/api/api.dart +++ b/Sources/dafl_project_flutter/lib/api/api.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:http/http.dart' as http; import 'package:crypto/crypto.dart'; import 'dart:developer' as dev; +import '../exceptions/api_exception.dart'; import 'track.dart'; class Api { @@ -12,12 +13,14 @@ class Api { //for web api get redirectUri => 'https://daflmusic.000webhostapp.com/callback/'; - final _scopes = 'user-read-playback-state user-read-currently-playing'; + final _scopes = + 'user-read-playback-state user-read-currently-playing user-read-recently-played'; late String _state; dynamic _codeVerifier; dynamic _codeChallenge; late String _encodedLogs; final _tokenType = 'Bearer '; + late http.Response _response; //use _setResponse() as kind of a private setter //from web api String? _code; @@ -74,11 +77,11 @@ class Api { //session management requestUserAuthorization(Uri url) async { - if (url.queryParameters['state'] == _state.toString()) { - _code = url.queryParameters['code']; - await _requestAccessToken(); + if (url.queryParameters['state'] != _state.toString()) { + throw ApiException(); } - // TODO : implement the else + _code = url.queryParameters['code']; + await _requestAccessToken(); } _requestAccessToken() async { @@ -89,18 +92,19 @@ class Api { 'client_id': _clientId, 'code_verifier': _codeVerifier }); - var response = await _client.post(urlToken, headers: { + _setResponse(await _client.post(urlToken, headers: { 'Authorization': 'Basic $_encodedLogs', 'Content-Type': 'application/x-www-form-urlencoded' - }); - var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map; + })); + 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 { + //handle 401 status code (bad or expired token) + Future _getAccessToken() async { await _tokenValidity(); return _accessToken; } @@ -111,16 +115,23 @@ class Api { } } + _setResponse(value) { + if (value.statusCode != 200) { + throw ApiException(); + } + _response = value; + } + _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: { + _setResponse(await _client.post(urlToken, headers: { 'Content-Type': 'application/x-www-form-urlencoded' - }); - var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map; + })); + var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map; _accessToken = decodedResponse['access_token']; _expiresIn = decodedResponse['expires_in']; _tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!)); @@ -128,29 +139,40 @@ class Api { //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: { + Future getRecentlyPlayedTrack() async { + var url = Uri.https( + 'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'}); + var token = await _getAccessToken(); + _setResponse(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']; + })); + var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map; + return decodedResponse['items'][0]['track']['id']; } Future getTrackInfo(String id) async { var url = Uri.https('api.spotify.com', 'v1/tracks/$id'); - var token = await _getToken(); - var response = await _client.get(url, headers: { + var token = await _getAccessToken(); + _setResponse(await _client.get(url, headers: { 'Authorization': '$_tokenType $token', 'Content-Type': 'application/json' - }); - var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map; - return Track( - decodedResponse['artists'][0]['name'], - decodedResponse['name'], - decodedResponse['album']['images'] - [decodedResponse['album']['images'].length - 1]['url']); + })); + var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map; + return Track(decodedResponse['artists'][0]['name'], decodedResponse['name'], + decodedResponse['album']['images'][0]['url']); + } + + getPlaylists() async { + var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'}); + var token = await _getAccessToken(); + _setResponse(await _client.get(url, headers: { + 'Authorization': '$_tokenType $token', + 'Content-Type': 'application/json' + })); + var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map; + dev.log(decodedResponse['items'] + .where((element) => element['name'] == 'daflmusic') + .toString()); } } diff --git a/Sources/dafl_project_flutter/lib/api/in_app_browser.dart b/Sources/dafl_project_flutter/lib/api/in_app_browser.dart index 81bc685..a04764b 100644 --- a/Sources/dafl_project_flutter/lib/api/in_app_browser.dart +++ b/Sources/dafl_project_flutter/lib/api/in_app_browser.dart @@ -1,6 +1,9 @@ import 'dart:io'; -import 'package:dafl_project_flutter/main.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'dart:developer' as dev; +import '../exceptions/api_exception.dart'; +import '../main.dart'; +import 'track.dart'; class MyInAppBrowser extends InAppBrowser { var options = InAppBrowserClassOptions( @@ -24,11 +27,19 @@ class MyInAppBrowser extends InAppBrowser { @override Future onLoadStart(url) async { if (url!.origin + url.path == MyApp.api.redirectUri) { - await MyApp.api.requestUserAuthorization(url); - /*String id = await MyApp.api.getCurrentlyPlayingTrack(); - Track track = await MyApp.api.getTrackInfo(id); - print('${track.artist} ${track.name} ${track.albumImage}');*/ - close(); + try { + await MyApp.api.requestUserAuthorization(url); + + /*String id = await MyApp.api.getRecentlyPlayedTrack(); + Track track = await MyApp.api.getTrackInfo(id); + dev.log('${track.artist} ${track.name} ${track.albumImage}');*/ + + await MyApp.api.getPlaylists(); + } on ApiException { + // TODO : add notification to show that an error occured + } finally { + close(); + } } } } diff --git a/Sources/dafl_project_flutter/lib/exceptions/api_exception.dart b/Sources/dafl_project_flutter/lib/exceptions/api_exception.dart new file mode 100644 index 0000000..53fe102 --- /dev/null +++ b/Sources/dafl_project_flutter/lib/exceptions/api_exception.dart @@ -0,0 +1,7 @@ +import 'dart:developer' as dev; + +class ApiException implements Exception { + ApiException() { + dev.log('Api exception raised'); + } +}