strava_flutter 1.0.11+26

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 79

strava_flutter #

Dart/flutter package to use Strava API v3

Follow the "new" Authentication process

https://developers.strava.com/docs/authentication/

API currently supported: #

Authentication #

  • authorize
  • deauthorize
  • getLoggedInAthlete
  • updateLoggedInAthlete (scope profile:write)
  • getLoggedInAthleteActivities (not limited)
  • getLoggedInAthleteZones
  • getGearById
  • getStats
  • getClubById
  • getClubActivitiesById
  • getClubMembersById
  • getRunningRaces
  • getRunningRaceById
  • createActivity
  • uploadActivity (includes getUploadById)
  • getSegmentById
  • getLoggedInAthleteStarredSegments
  • getLeaderboardBySegmentId (not limited)
  • starSegment

How to install #

Check on pub.dev/packages to see how to install this package

https://pub.dev/packages/strava_flutter#-installing-tab-

How to use it #

1 - Create a file secret.dart to put the secret shown on Strava settings related to your app https://www.strava.com/settings/api

2 - In constants.dart put your appID in clientID

3 - To see debug info in Strava API, set isInDebug to true in Strava() init

4 - Please check examples.dart for the moment

https://github.com/BirdyF/strava_flutter/blob/master/example/lib/main.dart

https://github.com/BirdyF/strava_flutter/blob/master/example/lib/examples.dart

If you have any problem or need an API not yet implemented please post a new issue

Tested on: #

  • Android 4.4.2 , 4.4.23
  • iOS 12.1, 12.1.2, 12.1.4

Contributors welcome! #

If you spot a problem/bug or if you consider that the code could be better please post an issue. I am not planning to implement all the Strava APIs, because I dont need all of them in my dev. But let me know if you need some APIs that are not in the current list and I will add it. Alternatively, you can easily implement additional API and I will add it to strava_futter.

Thanks #

Thanks to Joe Birch, I used his code to better understand Oauth process https://github.com/hitherejoe/FlutterOAuth

And Javier for https://javiercbk.github.io/json_to_dart/

License: #

strava_flutter is provided under a MIT License. Copyright (c) 2019 Patrick FINKELSTEIN

[0.0.1] - TODO: Add release date.

  • 1.0.10 added strava_prefix to preferences key
  • 1.0.11 removed lines in test

example/lib/main.dart

import 'package:flutter/material.dart';

import 'examples.dart';

import 'secret.dart'; // Where Strava app secret is stored

import 'package:strava_flutter/strava.dart';

// Used by example

import 'package:strava_flutter/Models/activity.dart';
import 'package:strava_flutter/Models/club.dart';
import 'package:strava_flutter/Models/detailedAthlete.dart';
import 'package:strava_flutter/Models/gear.dart';
import 'package:strava_flutter/Models/runningRace.dart';
import 'package:strava_flutter/Models/stats.dart';
import 'package:strava_flutter/Models/summaryAthlete.dart';
import 'package:strava_flutter/Models/zone.dart';
import 'package:strava_flutter/API/constants.dart';



Strava strava;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Strava Flutter',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: StravaFlutterPage(title: 'strava_flutter demo'),
    );
  }
}

class StravaFlutterPage extends StatefulWidget {
  StravaFlutterPage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _StravaFlutterPageState createState() => _StravaFlutterPageState();
}

class _StravaFlutterPageState extends State<StravaFlutterPage> {
  @override
  void initState() {
    setState(() {});
    super.initState();
  }

  void exampleStrava() {
    example(secret);
  }

  void exampleSeg() {
    exampleSegment(secret);
  }

  ///
  /// Example of dart code to use Strava API
  ///
  /// set isInDebug to true in strava init to see the debug info
  void example(String secret) async {
    bool isAuthOk = false;

    final strava = Strava(true, secret);
    final prompt = 'auto';

    isAuthOk = await strava.oauth(
        clientId,
        'activity:write,activity:read_all,profile:read_all,profile:write',
        secret,
        prompt);

    if (isAuthOk) {
      // Get the zones related to the logged athlete
      Zone _zone = await strava.getLoggedInAthleteZones();
      if (_zone.fault.statusCode != 200) {
        print(
            'Error in getLoggedInAthleteZones  ${_zone.fault.statusCode}  ${_zone.fault.message}');
      } else {
        _zone.infoZones.zones.forEach((zone) => print('getLoggedInAthleteZones ${zone.min} ${zone.max}'));
      }

      // Create an new activity
      String _startDate = '2019-02-18 10:02:13';
      DetailedActivity _newActivity = await strava.createActivity(
          'Test_Strava_Flutter', 'ride', _startDate, 3600,
          distance: 1555, description: 'This is a strava_flutter test');
      if (_newActivity.fault.statusCode != 201) {
        print(
            'Error in createActivity ${_newActivity.fault.statusCode}  ${_newActivity.fault.message}');
      } else {
        print('createActivity  ${_newActivity.name}');
      }

      // Type of expected answer:
      // {"id":25707617,"username":"patrick_ff","resource_state":3,"firstname":"Patrick","lastname":"FF",
      // "city":"Le Beausset","state":"Provence-Alpes-Côte d'Azur","country":"France","sex":null,"premium"
      DetailedAthlete _athlete = await strava.getLoggedInAthlete();
      if (_athlete.fault.statusCode != 200) {
        print(
            'Error in getloggedInAthlete ${_athlete.fault.statusCode}  ${_athlete.fault.message}');
      } else {
        print('getLoggedInAthlete ${_athlete.firstname}  ${_athlete.lastname}');
      }

      // Type of expected answer
      //  {"biggest_ride_distance":156733.0,"biggest_climb_elevation_gain":null,"recent_ride_totals":{"count":2,"distance":111427.7001953125,
      // "moving_time":17726,"elapsed_time":23181,"elevation_gain":1354.5838375091553,"achievement_count":0},"recent_run_to
      Stats _stats = await strava.getStats(_athlete.id);
      if (_stats.fault.statusCode != 200) {
        print(
            'Error in getStats ${_stats.fault.statusCode}    ${_stats.fault.message}');
      } else {
        print('getStats ${_stats.ytdRideTotals.distance} ${_stats.ytdRideTotals.elevationGain}   ${ _stats.allSwimTotals.distance}');
      }

      // A long list of races per city
      // Starting by Walt Disney World Marathon
      List<RunningRace> _listRunningRaces =
          await strava.getRunningRaces('2019');
      if ((_listRunningRaces == null) ||
          (_listRunningRaces[0].fault.statusCode != 200)) {
        print(
            'Error in getRunningRaces: ${_listRunningRaces[0].fault.statusCode}    ${_listRunningRaces[0].fault.message}');
      } else {
        print('getRunningRaces ${_listRunningRaces[0].name}');
      }

      // id corresponding to BMW Berlin Marathon 29th Sept 2019
      RunningRace _race = await strava.getRunningRaceById('2724');
      if (_race.fault.statusCode != 200) {
        print(
            'Error in getRunningRaceById  ${_race.fault.statusCode}    ${_race.fault.message}');
      } else {
        print('getRunningRaceById $_race');
      }

      // Change weight of the loggedAthlete in profile (in kg)
      DetailedAthlete _athlete2 = await strava.updateLoggedInAthlete(80);
      if (_athlete2.fault.statusCode != 200) {
        print(
            'Error in updateLoggedInAthlete ${_athlete2.fault.statusCode}  ${_athlete2.fault.message}');
      } else {
        print('getRunningRaceById $_athlete2');
      }

      /// Gear should be owned by the loggedIn Athleted
      /// Type of expected answer:
      /// {"id":"b4366285","primary":true,"name":"Roubaix Specialized","resource_state":3,"distance":461692.0,
      /// "brand_name":"Specialized","model_name":"Roubaix Expert","frame_type":3,"description":"So comfortable!"}
      Gear _gear = await strava.getGearById("b4366285");
      if (_gear.fault.statusCode != 200) {
        print(
            'error code getGearById  ${_gear.fault.statusCode}  ${_gear.fault.message}');
      } else {
        print('getGearById $_gear');
      }

      // IMPORTANT ------
      //  You have to join this club to do the test
      final clubStravaMarseille = '226910';

      /// Answer expected:
      /// {"id":226910,"resource_state":3,"name":"STRAVA Marseille ",
      /// "profile_medium":"https://dgalywyr863hv.cloudfront.net/pictures/clubs/226910/5003423/3/medium.jpg","profile":"https://dgalywyr863hv.cloudfront.net/pictures/clubs/226910/5003423/3/larg
      Club _club = await strava.getClubById(clubStravaMarseille);
      if (_club.fault.statusCode != 200) {
        print(
            'error code getClubById  ${_club.fault.statusCode}  ${_club.fault.message}');
      } else {
        print('getClubById $_club');
      }

      /// List the member of Strava club
      /// Expected answer (should start like this):
      ///  [{"resource_state":2,"firstname":"Adam","lastname":"Š.","membership":"member",
      /// "admin":false,"owner":false},{"resource_state":2,"firstname":"Alex","lastname":"M.","membership"
      List<SummaryAthlete> _listMembers = await strava.getClubMembersById('1');
      if (_listMembers[0].fault.statusCode != 200) {
        print(
            'error code getClubById  ${_club.fault.statusCode}  ${_club.fault.message}');
      } else {
        print('getClubMembersById ');
        _listMembers.forEach((member) => print(
            '${member.firstname}   ${member.lastname}  ${member.membership}'));
      }

      List<SummaryActivity> _listSumm =
          await strava.getClubActivitiesById(clubStravaMarseille);
      if (_listSumm[0].fault.statusCode != 200) {
        print(
            'error code getClubById  ${_club.fault.statusCode}  ${_club.fault.message}');
      } else {
        print('getClubActivitiesById ');
        _listSumm.forEach((activity) =>
            print('${activity.name}   ${activity.totalElevationGain}'));
      }

      /// You have to put an id of one activity of the logged Athlete
      /// You can find the id of one activity looking at your web page
      /// https://www.strava.com/activities/2130215349
      DetailedActivity _activity = await strava.getActivityById('2130215349');
      if (_activity.fault.statusCode != 200) {
        print('Error in getActivityById: ${_activity.fault.statusCode}');
      } else {
        print('getActivityById ${_activity.name}');
      }
    }
  }

  void upload() {
    print('Trying to upload');

    showDialog(
        context: context,
        builder: (BuildContext context) {
          return Center(
            child: CircularProgressIndicator(),
          );
        });

    var fault = exampleUpload(secret);
  }

  void 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();
  }

  @override
  void dispose() {
    strava.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(''),
            Text('Authentication'),
            Text('with segments Apis'),
            RaisedButton(
              key : Key('SegmentsButton'),
              child: Text('Segments'),
              // onPressed: exampleStrava,
              onPressed: exampleSeg,
            ),
            Text(''),
            Text('Authentication'),
            Text('with other Apis'),
            RaisedButton(
              key: Key('OthersButton'),
              child: Text('strava_flutter'),
              onPressed: exampleStrava,
            ),
            Text(''),
            Text(''),
            Text('Upload with authentication'),
            RaisedButton(
              key: Key('Uploadbutton'),
              child: Text('upload'),
              onPressed: upload,
            ),
            Text(' '),
            Text(''),
            Text(''),
            Text('Push this button'),
            Text(
              'to revoke/DeAuthorize Strava user',
            ),
            RaisedButton(
              key: Key('DeAuthorizeButton'),
              child: Text('DeAuthorize'),
              onPressed: deAuthorize,
            ),
          ],
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  strava_flutter: ^1.0.11+26

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:strava_flutter/API/Oauth.dart';
import 'package:strava_flutter/API/activities.dart';
import 'package:strava_flutter/API/athletes.dart';
import 'package:strava_flutter/API/clubs.dart';
import 'package:strava_flutter/API/constants.dart';
import 'package:strava_flutter/API/races.dart';
import 'package:strava_flutter/API/segments.dart';
import 'package:strava_flutter/API/upload.dart';
import 'package:strava_flutter/Models/OldsummaryActivity.dart';
import 'package:strava_flutter/Models/activity.dart';
import 'package:strava_flutter/Models/club.dart';
import 'package:strava_flutter/Models/detailedAthlete.dart';
import 'package:strava_flutter/Models/fault.dart';
import 'package:strava_flutter/Models/gear.dart';
import 'package:strava_flutter/Models/runningRace.dart';
import 'package:strava_flutter/Models/segment.dart';
import 'package:strava_flutter/Models/stats.dart';
import 'package:strava_flutter/Models/summaryAthlete.dart';
import 'package:strava_flutter/Models/token.dart';
import 'package:strava_flutter/Models/uploadActivity.dart';
import 'package:strava_flutter/Models/zone.dart';
import 'package:strava_flutter/globals.dart';
import 'package:strava_flutter/strava.dart';
  
Version Uploaded Documentation Archive
1.0.11+26 Jun 2, 2019 Go to the documentation of strava_flutter 1.0.11+26 Download strava_flutter 1.0.11+26 archive
1.0.11+25 May 14, 2019 Go to the documentation of strava_flutter 1.0.11+25 Download strava_flutter 1.0.11+25 archive
1.0.9+23 Apr 9, 2019 Go to the documentation of strava_flutter 1.0.9+23 Download strava_flutter 1.0.9+23 archive
1.0.8+22 Apr 3, 2019 Go to the documentation of strava_flutter 1.0.8+22 Download strava_flutter 1.0.8+22 archive
1.0.8+21 Apr 2, 2019 Go to the documentation of strava_flutter 1.0.8+21 Download strava_flutter 1.0.8+21 archive
1.0.7+21 Apr 2, 2019 Go to the documentation of strava_flutter 1.0.7+21 Download strava_flutter 1.0.7+21 archive
1.0.6+20 Mar 26, 2019 Go to the documentation of strava_flutter 1.0.6+20 Download strava_flutter 1.0.6+20 archive
1.0.6+19 Mar 25, 2019 Go to the documentation of strava_flutter 1.0.6+19 Download strava_flutter 1.0.6+19 archive
1.0.6+18 Mar 25, 2019 Go to the documentation of strava_flutter 1.0.6+18 Download strava_flutter 1.0.6+18 archive
1.0.6+17 Mar 23, 2019 Go to the documentation of strava_flutter 1.0.6+17 Download strava_flutter 1.0.6+17 archive

All 24 versions...

Popularity:
Describes how popular the package is relative to other packages. [more]
59
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
79
Learn more about scoring.

We analyzed this package on Jun 12, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.3.1
  • pana: 0.12.17
  • Flutter: 1.5.4-hotfix.2

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health issues and suggestions

Document public APIs. (-0.24 points)

1008 out of 1035 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Format lib/globals.dart.

Run flutter format to format lib/globals.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
cupertino_icons ^0.1.2 0.1.2
flutter 0.0.0
http ^0.12.0+1 0.12.0+2
path_provider ^0.5.0+1 0.5.0+1 1.1.0
shared_preferences ^0.5.0 0.5.3+1
url_launcher ^5.0.2 5.0.3
Transitive dependencies
async 2.2.0
charcode 1.1.2
collection 1.14.11
http_parser 3.1.3
meta 1.1.6 1.1.7
path 1.6.2
pedantic 1.7.0
sky_engine 0.0.99
source_span 1.5.5
string_scanner 1.0.4
term_glyph 1.1.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test