Début implémentation MVC.
continuous-integration/drone/push Build is failing Details

/!\ toutes les erreurs ne sont pas résolus !
remotes/origin/mvc-implementation
Félix MIELCAREK 2 years ago
parent 4528871a81
commit b085106f28

@ -1,300 +0,0 @@
import 'dart:convert';
import 'dart:math';
import 'package:dafl_project_flutter/main.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'dart:developer' as dev;
import '../exceptions/api_exception.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 user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
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
final _playlistName = "Dafl's discovery";
//from web api
String? _code;
int? _expiresIn;
String? _refreshToken;
String? _accessToken; //use _getAccessToken() 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();
_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() {
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
.replaceAll('+', '-')
.replaceAll('/', '_')
.replaceAll('=', '');
}
//session management
requestUserAuthorization(Uri url) async {
if (url.queryParameters['state'] != _state.toString()) {
throw ApiException('state');
}
_code = url.queryParameters['code'];
await _requestAccessToken();
}
_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
});
_setResponse(await _client.post(urlToken, headers: <String, String>{
'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<String?> _getAccessToken() async {
if (DateTime.now().isAfter(_tokenEnd!)) {
await _getRefreshedAccessToken();
}
return _accessToken;
}
_setResponse(value) {
int sc = value.statusCode;
if (sc >= 300) {
dev.log(value.body.toString());
throw ApiException(sc);
}
_response = value;
}
_getRefreshedAccessToken() async {
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
'grant_type': 'refresh_token',
'refresh_token': _refreshToken,
'client_id': _clientId
});
_setResponse(await _client.post(urlToken, headers: <String, String>{
'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<String> getCurrentlyPlayingTrack() async {
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
var token = await _getAccessToken();
var response = await _client.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
});
if (response.statusCode == 204) {
return _getRecentlyPlayedTrack();
}
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
return decodedResponse['item']['id'];
}
Future<String> _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: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
return decodedResponse['items'][0]['track']['id'];
}
Future<Map> getTrackInfo(String id) async {
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
var token = await _getAccessToken();
_setResponse(await _client.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
Map<String, String> info = {
'artist': decodedResponse['artists'][0]['name'],
'name': decodedResponse['name'],
'cover': decodedResponse['album']['images'][0]['url']
};
return info;
}
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
{'limit': '50', 'fields': 'items(track(id))'});
var token = await _getAccessToken();
_setResponse(await _client.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
var res = decodedResponse['items']
.where((element) => element['track']['id'] == idTrack)
.toList();
if (res.length >= 1) {
return true;
}
return false;
}
addToPLaylist(String idTrack) async {
var idPlaylist = await _getPlaylist();
if (idPlaylist == null) {
idPlaylist = await _createPlaylist();
} else {
if (await _isInPlaylist(idTrack, idPlaylist)) {
return;
}
}
var token = await _getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
{'uris': 'spotify:track:$idTrack'});
_setResponse(await _client.post(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
}
Future<String?> _getPlaylist() async {
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
var token = await _getAccessToken();
_setResponse(await _client.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
var daflplaylist = decodedResponse['items']
.where((element) => element['name'] == _playlistName)
.toList();
if (daflplaylist.length == 1) {
return daflplaylist[0]['uri'].substring(
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
}
return null;
}
Future<String> _createPlaylist() async {
var idUser = await MyApp.controller.currentUser.getIdSpotify();
var token = await _getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
_setResponse(await _client.post(url,
headers: <String, String>{
'Accept': 'application/json',
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonEncode(<String, String>{
'name': _playlistName,
'description':
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
'public': 'true'
})));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
var idPlaylist = decodedResponse['id'];
return idPlaylist;
}
playTrack(String idTrack) async {
var token = await _getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
_setResponse(await _client.put(url,
headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonEncode(<String, List>{
'uris': ['spotify:track:$idTrack']
})));
}
removeFromPlaylist(String idTrack) async {
var idPlaylist = await _getPlaylist();
if (idPlaylist != null) {
if (await _isInPlaylist(idTrack, idPlaylist)) {
var token = await _getAccessToken();
var url =
Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
var jsonVar = jsonEncode(<String, List>{
'tracks': [
{'uri': 'spotify:track:$idTrack'}
]
});
_setResponse(await _client.delete(url,
headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonVar));
}
}
}
Future<String> getIdUser() async {
var url = Uri.https('api.spotify.com', 'v1/me');
var token = await _getAccessToken();
_setResponse(await _client.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
return decodedResponse['id'];
}
}

@ -1,45 +1,74 @@
import 'dart:convert';
import 'package:dafl_project_flutter/model/music.dart';
import 'package:dafl_project_flutter/services/api/api_spotify.dart';
import 'package:dafl_project_flutter/services/position/area.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import '../persistence/database_loader.dart';
import '../persistence/database_saver.dart';
import '../persistence/database_searcher.dart';
import '../persistence/loader.dart';
import '../persistence/saver.dart';
import '../model/spot.dart';
import '../model/user.dart';
import '../persistence/searcher.dart';
class Controller {
static Saver saver = DatabaseSaver();
static Loader loader = DatabaseLoader();
static final Searcher _searcher = DatabaseSearcher();
ApiSpotify _api = ApiSpotify();
late User _currentUser;
Area _area = Area();
late BuildContext navigatorKey;
Uri getApiUrlAuthorize() {
return _api.identification.urlAuthorize;
}
late User currentUser;
String getApiRedirectUrl() {
return _api.identification.redirectUri;
}
Controller() {
currentUser = User('', ''); //TODO : remove this line
apiAuthorization(url) {
_api.apiAuthorization(url);
}
String getIdSpotify() {
return _currentUser.idSpotify;
}
Future<Music> getCompleteMusic(String id) async {
Map infos = await _api.requests.getTrackInfo(id);
return Music(id, infos['name'], infos['artist'], infos['cover']);
}
setCurrentMusic() async {
_currentUser.currentMusic = await _api.requests.getCurrentlyPlayingTrack();
}
String getCurrentMusic() {
return _currentUser.currentMusic;
}
int getIdDafl() {
return _currentUser.idDafl;
}
List<Spot> getSpots() {
return _area.spots;
}
/*
static Saver saver = DatabaseSaver();
static Loader loader = DatabaseLoader();
static final Searcher _searcher = DatabaseSearcher();
late BuildContext navigatorKey;
void save(User userToSave) {
saver.save(userToSave);
}
load(String username, String password) async {
_changeCurrentUser(await loader.load(username, password));
}
_changeCurrentUser(User user) {
currentUser = user;
//TODO : call database methode + create user
}
changeCurrentUsername(String newName) {
currentUser.usernameDafl = newName;
changeUsername(String newName) {
//TODO : call database method
}
changeCurrentPassword(String newPass) {
currentUser.passwDafl = newPass;
//TODO : call database method
}
Future<bool> searchByUsername(String username) async {
@ -71,4 +100,5 @@ class Controller {
}),
);
}
*/
}

@ -1,13 +0,0 @@
import 'dart:developer' as dev;
class ApiException implements Exception {
final String mess = 'Api exception raised,';
ApiException(dynamic code) {
if (code.runtimeType == String) {
dev.log('$mess state verification failed.');
} else {
dev.log('$mess status code : $code.');
}
}
}

@ -0,0 +1,7 @@
import 'dart:developer' as dev;
class ApiStateException implements Exception {
ApiStateException() {
dev.log('State verification failed.');
}
}

@ -0,0 +1,9 @@
import 'dart:developer' as dev;
class HttpException implements Exception {
HttpException(var value) {
dev.log('Http request failed :');
dev.log('Status code : ${value.statusCode.toString()}');
dev.log('Body : ${value.body.toString()}');
}
}

@ -9,7 +9,6 @@ import 'package:provider/provider.dart';
import 'package:rive/rive.dart' as riv;
import '../controller/controller.dart';
import 'model/spot.dart';
import 'api/api.dart';
import 'dart:developer' as dev;
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
@ -19,7 +18,6 @@ void main() {
class MyApp extends StatelessWidget {
static Controller controller = Controller();
static Api api = Api();
const MyApp({super.key});
@ -31,7 +29,7 @@ class MyApp extends StatelessWidget {
SystemUiMode.manual,
overlays: [SystemUiOverlay.top],
);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.dark, // For Android (dark icons)
statusBarBrightness: Brightness.dark, // For iOS (dark icons)
));
@ -48,7 +46,7 @@ class MyApp extends StatelessWidget {
enum CardStatus { like, disLike, discovery, message }
class CardProvider extends ChangeNotifier {
final List<Spot> _spotsList = MyApp.controller.currentUser.spots;
final List<Spot> _spotsList = MyApp.controller.getSpots();
bool _isDragging = false;
double _angle = 0;
Offset _position = Offset.zero;
@ -196,7 +194,7 @@ class CardProvider extends ChangeNotifier {
width: 10,
),
MyApp.controller.currentUser.discovery.contains(
MyApp.controller.currentUser.spots.last.music)
MyApp.controller.getSpots().last.music)
? const Text(
"Déjà dans vos discovery",
style: TextStyle(
@ -220,10 +218,10 @@ class CardProvider extends ChangeNotifier {
reverseCurve: Curves.linear,
);
if (!MyApp.controller.currentUser.discovery
.contains(MyApp.controller.currentUser.spots.last.music)) {
MyApp.controller.currentUser.spots.last.music.defineDate();
.contains(MyApp.controller.getSpots().last.music)) {
MyApp.controller.getSpots().last.music.defineDate();
MyApp.controller.currentUser
.addDiscovery(MyApp.controller.currentUser.spots.last.music);
.addDiscovery(MyApp.controller.getSpots().last.music);
notifyListeners();
}
}
@ -333,7 +331,7 @@ class CardProvider extends ChangeNotifier {
child: ElevatedButton(
onPressed: () {
sendMessage(messageTextField.text,
MyApp.controller.currentUser.spots.last.userId);
MyApp.controller.getSpots().last.userId);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF3F1DC3),
@ -364,7 +362,7 @@ class CardProvider extends ChangeNotifier {
}
void sendMessage(String message, String userId) {
dev.log(MyApp.controller.currentUser.spots.last.userId);
dev.log(MyApp.controller.getSpots().last.userId);
}
void like(context) {

@ -1,32 +1,22 @@
import '../exceptions/api_exception.dart';
import '../exceptions/api_state_exception.dart';
import '../main.dart';
class Music {
late String _name;
late String _artist;
late String _linkCover;
final String _id;
late DateTime date;
final String _name;
final String _artist;
final String _linkCover;
Music(this._id) {
_completeInfo();
}
Music(this._id, this._name, this._artist, this._linkCover);
String get id => _id;
String get name => _name;
String get artist => _artist;
String get linkCover => _linkCover;
String get id => _id;
_completeInfo() async {
try {
var info = await MyApp.api.getTrackInfo(_id);
_name = info['name'];
_artist = info['artist'];
_linkCover = info['cover'];
} on ApiException {
// TODO : add notification to show that an error occured
}
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
@ -37,8 +27,4 @@ class Music {
@override
int get hashCode => name.hashCode ^ artist.hashCode;
void defineDate() {
this.date = new DateTime.now();
}
}

@ -1,6 +1,4 @@
import 'dart:async';
import '../../../position/location.dart';
import '../exceptions/api_exception.dart';
import '../main.dart';
import 'music.dart';
import 'spot.dart';
@ -17,34 +15,20 @@ class User {
List<Spot> spots = [];
//attributes with Spotify API
String? _idSpotify; //use _getIdUser() as kind of a private getter
late Music _currentMusic;
final String _idSpotify;
late String currentMusic;
bool sortChoise = true;
//constructors
User(this.usernameDafl, this.passwDafl) {
actualiseCurrentMusic();
}
User(this.usernameDafl, this._idSpotify);
Music get currentMusic => _currentMusic; //lists
Future<String> getIdSpotify() async {
_idSpotify ??= await MyApp.api.getIdUser();
return _idSpotify!;
}
String get idSpotify => _idSpotify;
addDiscovery(Music music) {
discovery.add(music);
}
actualiseCurrentMusic() async {
try {
_currentMusic = Music(await MyApp.api.getCurrentlyPlayingTrack());
} on ApiException {
// TODO : add notification to show that an error occurred
}
}
listSpots() {
int verif = 0;
Future<Map<String, dynamic>> rep = Location.sendCurrentLocation();
@ -64,6 +48,5 @@ class User {
});
}
});
}
}

@ -1,5 +0,0 @@
import '../model/user.dart';
abstract class Saver{
void save(User userToSave);
}

@ -0,0 +1,20 @@
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
import 'package:dafl_project_flutter/services/api/api_spotify_requests.dart';
class ApiSpotify {
late ApiSpotifyIdentification _identification;
late ApiSpotifyRequests _requests;
ApiSpotify() {
_identification = ApiSpotifyIdentification();
}
ApiSpotifyIdentification get identification => _identification;
ApiSpotifyRequests get requests => _requests;
apiAuthorization(url) async {
await _identification.setCode(url);
_requests = ApiSpotifyRequests(await _identification.createToken());
}
}

@ -0,0 +1,83 @@
import 'dart:convert';
import 'dart:math';
import '../../exceptions/api_state_exception.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import '../http_response_verification.dart';
import 'token_spotify.dart';
class ApiSpotifyIdentification extends HttpResponseVerification {
static const String clientId = '7ceb49d874b9404492246027e4d68cf8';
final String _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
final String _scopes =
'user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
late String _state;
late String _codeVerifier;
late String _codeChallenge;
late String _encodedLogs;
String? _code;
String get redirectUri => 'https://daflmusic.000webhostapp.com/callback/';
Uri get 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
});
ApiSpotifyIdentification() {
_state = _generateRandomString(16);
_codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
_codeChallenge = _generateCodeChallenge();
_encodedLogs = base64.encode(utf8.encode("$clientId:$_clientSecret"));
}
_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() {
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
.replaceAll('+', '-')
.replaceAll('/', '_')
.replaceAll('=', '');
}
setCode(Uri url) async {
if (url.queryParameters['state'] != _state.toString()) {
throw ApiStateException();
}
_code = url.queryParameters['code'];
}
Future<TokenSpotify> createToken() 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
});
setResponse(await http.post(urlToken, headers: <String, String>{
'Authorization': 'Basic $_encodedLogs',
'Content-Type': 'application/x-www-form-urlencoded'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
return TokenSpotify(decodedResponse['access_token'],
decodedResponse['refresh_token'], decodedResponse['expires_in']);
}
}

@ -0,0 +1,177 @@
import 'dart:convert';
import 'package:dafl_project_flutter/services/api/token_spotify.dart';
import 'package:http/http.dart' as http;
import '../../main.dart';
import '../http_response_verification.dart';
class ApiSpotifyRequests extends HttpResponseVerification {
final String _tokenType = 'Bearer ';
final String _playlistName = "Dafl's discovery";
final TokenSpotify _token;
ApiSpotifyRequests(this._token);
Future<String> getCurrentlyPlayingTrack() async {
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
var token = await _token.getAccessToken();
var response = await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
});
if (response.statusCode == 204) {
return _getRecentlyPlayedTrack();
}
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
return decodedResponse['item']['id'];
}
Future<String> _getRecentlyPlayedTrack() async {
var url = Uri.https(
'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'});
var token = await _token.getAccessToken();
setResponse(await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
return decodedResponse['items'][0]['track']['id'];
}
Future<Map> getTrackInfo(String id) async {
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
var token = await _token.getAccessToken();
setResponse(await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
Map<String, String> infos = {
'artist': decodedResponse['artists'][0]['name'],
'name': decodedResponse['name'],
'cover': decodedResponse['album']['images'][0]['url']
};
return infos;
}
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
{'limit': '50', 'fields': 'items(track(id))'});
var token = await _token.getAccessToken();
setResponse(await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
var res = decodedResponse['items']
.where((element) => element['track']['id'] == idTrack)
.toList();
if (res.length >= 1) {
return true;
}
return false;
}
addToPLaylist(String idTrack) async {
var idPlaylist = await _getPlaylist();
if (idPlaylist == null) {
idPlaylist = await _createPlaylist();
} else {
if (await _isInPlaylist(idTrack, idPlaylist)) {
return;
}
}
var token = await _token.getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
{'uris': 'spotify:track:$idTrack'});
setResponse(await http.post(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
}
Future<String?> _getPlaylist() async {
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
var token = await _token.getAccessToken();
setResponse(await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
var daflplaylist = decodedResponse['items']
.where((element) => element['name'] == _playlistName)
.toList();
if (daflplaylist.length == 1) {
return daflplaylist[0]['uri'].substring(
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
}
return null;
}
Future<String> _createPlaylist() async {
var idUser = MyApp.controller.getIdSpotify();
var token = await _token.getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
setResponse(await http.post(url,
headers: <String, String>{
'Accept': 'application/json',
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonEncode(<String, String>{
'name': _playlistName,
'description':
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
'public': 'true'
})));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
var idPlaylist = decodedResponse['id'];
return idPlaylist;
}
playTrack(String idTrack) async {
var token = await _token.getAccessToken();
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
setResponse(await http.put(url,
headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonEncode(<String, List>{
'uris': ['spotify:track:$idTrack']
})));
}
removeFromPlaylist(String idTrack) async {
var idPlaylist = await _getPlaylist();
if (idPlaylist != null) {
if (await _isInPlaylist(idTrack, idPlaylist)) {
var token = await _token.getAccessToken();
var url =
Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
var jsonVar = jsonEncode(<String, List>{
'tracks': [
{'uri': 'spotify:track:$idTrack'}
]
});
setResponse(await http.delete(url,
headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
},
body: jsonVar));
}
}
}
Future<String> getIdUser() async {
var url = Uri.https('api.spotify.com', 'v1/me');
var token = await _token.getAccessToken();
setResponse(await http.get(url, headers: <String, String>{
'Authorization': '$_tokenType $token',
'Content-Type': 'application/json'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
return decodedResponse['id'];
}
}

@ -1,8 +1,6 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import '../exceptions/api_exception.dart';
import '../main.dart';
import '../../main.dart';
class MyInAppBrowser extends InAppBrowser {
var options = InAppBrowserClassOptions(
@ -14,7 +12,8 @@ class MyInAppBrowser extends InAppBrowser {
MyInAppBrowser() {
_debugBrowser();
openUrlRequest(
urlRequest: URLRequest(url: MyApp.api.urlAuthorize), options: options);
urlRequest: URLRequest(url: MyApp.controller.getApiUrlAuthorize()),
options: options);
}
_debugBrowser() async {
@ -26,10 +25,10 @@ class MyInAppBrowser extends InAppBrowser {
@override
Future onLoadStart(url) async {
bool isError = false;
if (url!.origin + url.path == MyApp.api.redirectUri) {
if (url!.origin + url.path == MyApp.controller.getApiRedirectUrl()) {
try {
await MyApp.api.requestUserAuthorization(url);
} on ApiException {
await MyApp.controller.apiAuthorization(url);
} catch (e) {
notify(5, MyApp.controller.navigatorKey);
isError = true;
} finally {

@ -0,0 +1,41 @@
import 'dart:convert';
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
import '../http_response_verification.dart';
import 'package:http/http.dart' as http;
class TokenSpotify extends HttpResponseVerification {
String _accessToken;
final String _refreshToken;
late DateTime _tokenEnd;
TokenSpotify(this._accessToken, this._refreshToken, int expiresIn) {
_setTokenEnd(expiresIn);
}
_setTokenEnd(int expiresIn) {
_tokenEnd = DateTime.now().add(Duration(seconds: expiresIn));
}
Future<String> getAccessToken() async {
if (DateTime.now().isAfter(_tokenEnd)) {
await _actualiseToken();
}
return _accessToken;
}
_actualiseToken() async {
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
'grant_type': 'refresh_token',
'refresh_token': _refreshToken,
'client_id': ApiSpotifyIdentification.clientId
});
setResponse(await http.post(urlToken, headers: <String, String>{
'Content-Type': 'application/x-www-form-urlencoded'
}));
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
_accessToken = decodedResponse['access_token'];
_setTokenEnd(decodedResponse['expires_in']);
}
}

@ -0,0 +1,17 @@
import 'package:flutter/cupertino.dart';
import '../exceptions/http_exception.dart';
import 'package:http/http.dart' as http;
abstract class HttpResponseVerification {
@protected
late http.Response response;
@protected
setResponse(var value) {
if (value.statusCode >= 300) {
throw HttpException(value);
}
response = value;
}
}

@ -1,6 +1,6 @@
import 'dart:async';
import 'loader.dart';
import '../model/user.dart';
import '../../model/user.dart';
import 'database_connexion.dart';
import 'dart:developer' as dev;

@ -1,6 +1,6 @@
import 'database_connexion.dart';
import 'saver.dart';
import '../model/user.dart';
import '../../model/user.dart';
class DatabaseSaver extends Saver {
// Save user in the database

@ -1,5 +1,5 @@
import 'dart:async';
import '../model/user.dart';
import '../../model/user.dart';
abstract class Loader {
Future<User> load(String username, String password);

@ -0,0 +1,5 @@
import '../../model/user.dart';
abstract class Saver {
void save(User userToSave);
}

@ -2,42 +2,41 @@ import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import '../main.dart';
class Location {
static Future<Map<String, dynamic>> sendCurrentLocation() async {
import '../../main.dart';
import '../../model/spot.dart';
class Area {
late List<Spot> spots;
sendCurrentLocation() async {
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/insert.php");
LocationPermission permission;
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.deniedForever) {
//faire l'interface gra pour gérer ça
return Future.error('Location Not Available');
//TODO : handle this case
}
}
String actualUser = MyApp.controller.currentUser.usernameDafl;
String actualSong = await MyApp.api.getCurrentlyPlayingTrack();
String actualUser = MyApp.controller.getIdSpotify();
String actualSong = await MyApp.controller.getCurrentMusic();
Position current = await Geolocator.getCurrentPosition();
await http.post(uri, body: {
"id": actualUser.toString(),
"id": actualUser,
"latitude": current.latitude.toString(),
"longitude": current.longitude.toString(),
"idMusic": actualSong.toString(),
"idMusic": actualSong
});
return getData();
}
static Future<Map<String, dynamic>> getData() async {
Map<String, dynamic> spot = {};
String actualUser = MyApp.controller.currentUser.usernameDafl;
getData() async {
String actualUser = MyApp.controller.getIdDafl().toString();
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/distance.php");
http.Response response = await http.post(uri, body: {
"id": actualUser,
});
var data = jsonDecode(response.body);
data.forEach((s)=> spot.putIfAbsent(s['user'], () => s['music']));
return spot;
data.forEach((s) => spots.add(Spot(s['user'], s['music'])));
}
}

@ -1,6 +1,20 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "50.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0"
animations:
dependency: "direct main"
description:
@ -78,6 +92,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
color:
dependency: transitive
description:
name: color
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
convert:
dependency: transitive
description:
@ -106,6 +127,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.4"
dartx:
dependency: transitive
description:
name: dartx
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
fake_async:
dependency: transitive
description:
@ -132,6 +167,20 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_gen:
dependency: "direct main"
description:
name: flutter_gen
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0+1"
flutter_gen_core:
dependency: transitive
description:
name: flutter_gen_core
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0+1"
flutter_inappwebview:
dependency: "direct main"
description:
@ -245,6 +294,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
graphs:
dependency: transitive
description:
@ -357,6 +413,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
page_transition:
dependency: "direct main"
description:
@ -462,6 +525,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.4"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
random_string:
dependency: "direct main"
description:
@ -530,6 +600,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.12"
time:
dependency: transitive
description:
name: time
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
typed_data:
dependency: transitive
description:
@ -558,6 +635,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.6"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
win32:
dependency: transitive
description:

@ -29,6 +29,7 @@ dependencies:
home_indicator: ^2.0.2
geolocator: ^9.0.2
flutter_styled_toast: ^2.1.3
flutter_gen: ^5.1.0+1
dev_dependencies:
flutter_test:

Loading…
Cancel
Save