dreampowder / strava_flutter

Flutter package to use Strava v3 API
Other
37 stars 52 forks source link

get current User and Upload Activity method #78

Closed yusmi25 closed 2 years ago

yusmi25 commented 2 years ago

hello @dreampowder, Is there any sample code to get current user when Application startup and example to upload activity. when I using version ^1.2.2+62 I'm using this code to upload activity and get current User ` // examples.dart

// Examples to use strava_flutter import 'dart:async'; import 'dart:io'; import 'package:flutter/services.dart' show rootBundle; import 'package:path_provider/path_provider.dart'; import 'dart:typed_data'; // Needed when declaring ByteData

// import 'package:strava_flutter/API/constants.dart'; import 'package:strava_flutter/errorCodes.dart' as error; import 'secret.dart';

// Used by uploadExample import 'package:strava_flutter/strava.dart'; import 'package:strava_flutter/Models/fault.dart'; import 'package:strava_flutter/Models/stats.dart'; // Test

// Used by segment and segmentEffort import 'package:strava_flutter/Models/segment.dart'; import 'package:strava_flutter/Models/segmentEffort.dart';

// To test getLoggedInAtletheActivities import 'package:strava_flutter/Models/detailedAthlete.dart'; import 'package:strava_flutter/Models/activity.dart';

/// Example showing how to upload an activity on Strava /// /// Use file Bormes.gpx in assets /// /// Should appear on your activities 6 Feb. 2019 /// /// Under the title Bormes3 /// Future uploadActivity(String secret, String path) async { String titleName; // Do authentication with the right scope final strava = Strava( true, // To get display info in API secret); Fault _fault = Fault(error.statusOk, 'Upload succesful');

bool isAuthOk = false;

isAuthOk = await strava.oauth(clientId, 'activity:write', secret, 'auto'); print('---> Authentication result: $isAuthOk'); if (isAuthOk == false) { _fault.statusCode = error.statusAuthError; _fault.message = 'Authentication has not been succesful'; return _fault; }

var hour = DateTime.now().hour; if (hour < 12) { titleName = 'Morning Ride'; } if (hour < 17) { titleName = 'Afternoon Ride'; } else { titleName = 'Evening Ride'; }

Fault fault = await strava.uploadActivity( titleName, 'Uploaded By Qimtronics', path, 'fit');

return fault; }

Future autStrava(String secret) async { // Do authentication with the right scope final strava = Strava( true, // To get display info in API secret);

bool isAuthOk = false;

isAuthOk = await strava.oauth(clientId, 'activity:write', secret, 'auto'); print('---> Authentication result: $isAuthOk'); return isAuthOk; }

Future deAuthorize() async { // need to get authorized before (valid token) final strava = Strava( true, // to get disply info in API secret, // Put your secret key in secret.dart file ); var fault = await strava.deAuthorize(); return fault; } ` Thank You.

mstreeter24 commented 2 years ago

It looks like there is a bug in the UploadActivityRequest model. I imported the code locally and fixed it and got it working with my own account. The main change that needs to be done is in the serialization/deserialization on the UploadActivityRequest object. They might have updated their property names to be underscore now instead of title case. These are the corrected serialization/deserialization methods.

I was going to push a pull request to fix it, but I believe I need permissions first.

UploadActivityRequest.fromJson(dynamic json) { name = json['name']; description = json['description']; isTrainerActivity = json['trainer']; isCommuteActivity = json['commute']; dataType = json['data_type']; externalId = json['external_id']; }

Map<String, dynamic> toJson() { var map = <String, dynamic>{}; map['name'] = name; map['description'] = description; map['trainer'] = isTrainerActivity; map['commute'] = isCommuteActivity; map['data_type'] = dataType; map['external_id'] = externalId; return map; }

As far as example code, this is what I used:

First you need to ensure you confiure your app link for authorization redirect:

`

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with YOUR_SCHEME://YOUR_HOST -->
<data
    android:scheme="YOUR_SCHEME"
    android:host="YOUR_HOST" />

`

The scheme and host can be anything, just ensure they are unique since they are globally shared across all apps.

For IOS in Info.plist:

`CFBundleURLTypes

CFBundleTypeRole None CFBundleURLName YOUR_HOST CFBundleURLSchemes YOUR_SCHEME ` With that configured here is a snippet of code I used from their latest code base printing status for debugging. You can pass it any accepted data file (.gpx, .tcx, .fit). Inside initState: `_stravaClient = StravaClient(secret: secret, clientId: clientId);` and then a method to upload: `void _syncWithStrava(RecordedRoute route) { _stravaClient.authentication.authenticate( scopes: [AuthenticationScope.activity_write], redirectUrl: Uri.encodeComponent("YOUR_SCHEME://YOUR_HOST") ).whenComplete(() { route.getGpxFile().then((File gpxFile) { _stravaClient.uploads.uploadActivity( UploadActivityRequest(file: gpxFile, name: route.name, dataType: 'gpx') ).then((value) => print(value.status)); }); }); }`
dreampowder commented 2 years ago

hi @mstreeter24 first of all thank you! a pull request with your fix would be a great contribution if you can, if not, can you please attach the modified files in here?

mstreeter24 commented 2 years ago

@dreampowder I believe somebody who has permissions would have to give me permission to edit the repo. I can add my changes on a bugfix branch if you give me permission.

If not the code fix is in my first post. Under domain/model/model_upload_request.dart replace the from and to json functions with:

UploadActivityRequest.fromJson(dynamic json) { name = json['name']; description = json['description']; isTrainerActivity = json['trainer']; isCommuteActivity = json['commute']; dataType = json['data_type']; externalId = json['external_id']; }

Map<String, dynamic> toJson() { var map = <String, dynamic>{}; map['name'] = name; map['description'] = description; map['trainer'] = isTrainerActivity; map['commute'] = isCommuteActivity; map['data_type'] = dataType; map['external_id'] = externalId; return map; }

mstreeter24 commented 2 years ago

@yusmi25 I am guessing you fixed your fault issue since I don't see the message even though I got the email? My guess is it was unrelated and something to do with payload format or something along those lines. This is the general flow I use to upload a file.

RecordedRoute is just an object with a list of points that have latitude, longitude, time stamps and altitude. It also has a stravaSync bool value that stores whether the route has already uploaded to Strava and a Strava upload id so it can get the status of unfinished uploads. response.error != null || response.externalId != null; is checking whether the upload errored out or succeeded.

From there I generate a GPX file with the gpx flutter library and then save it to a temporary directory before passing it to the uploadActivity call.

void syncWithStrava(RecordedRoute recordedRoute) { if (recordedRoute.stravaSync) { return; } Completer<TokenResponse> completer = Completer<TokenResponse>(); _stravaClient.authentication.authenticate( scopes: [AuthenticationScope.activityWrite], redirectUrl: Uri.encodeComponent(APP_REDIRECT_LINK) ).whenComplete(() { if (recordedRoute.stravaId != null) { _stravaClient.uploads.getUpload(recordedRoute.stravaId!).then( (UploadResponse response) { recordedRoute.stravaSync = response.error != null || response.externalId != null; _trailRouteDao.updateStrava(recordedRoute); } ).catchError((_) => Future.value(null)); } else { recordedRoute.getGpxFile().then((io.File gpxFile) { _stravaClient.uploads.uploadActivity( UploadActivityRequest(file: gpxFile, name: recordedRoute.name, dataType: 'gpx') ).then((UploadResponse response) { recordedRoute.stravaId = response.id; _trailRouteDao.updateStrava(recordedRoute); try { gpxFile.deleteSync(); } catch(e) { debugPrint('Exception during file remove.'); } }).catchError((_) => Future.value(null)); }); } }).catchError((_) => completer.future); }

dreampowder commented 2 years ago

@mstreeter24 I updated the code for UploadActivityRequest serializer. are the any other issue with the code?

mstreeter24 commented 2 years ago

@dreampowder There shouldn't be. That was the only change I made to my local copy to get it working. I was just giving him an example of how to use the library to get past his Fault issue which was probably related to a badly formatted GPX file. My example ignores exceptions and faults though, since I don't do anything about them anyway.