diff --git a/packages/stream_feeds/example/.gitignore b/packages/stream_feeds/example/.gitignore new file mode 100644 index 00000000..e4e2435f --- /dev/null +++ b/packages/stream_feeds/example/.gitignore @@ -0,0 +1,54 @@ +# For the example app on pub.dev we ignore all native platform folders, just run `flutter create .` to create them. +# Make sure you have internet permissions. +android/ +ios/ +macos/ +windows/ +linux/ +web/ + +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/stream_feeds/example/.metadata b/packages/stream_feeds/example/.metadata new file mode 100644 index 00000000..05a8ab44 --- /dev/null +++ b/packages/stream_feeds/example/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/stream_feeds/example/README.md b/packages/stream_feeds/example/README.md new file mode 100644 index 00000000..e3e01cc5 --- /dev/null +++ b/packages/stream_feeds/example/README.md @@ -0,0 +1,19 @@ +# Stream Feeds Example + +This is a very basic example of how to use the Stream Feeds SDK. +For a more complete example, you can check the [Stream Feeds sample app](https://github.com/GetStream/stream-feeds-flutter/tree/main/sample_app). + +## Getting Started + +To run the example, you need to get your own credentials from Stream and update the `lib/main.dart` file. +For more detailed documentation and examples, visit: +[https://getstream.io/activity-feeds/docs/flutter/](https://getstream.io/activity-feeds/docs/flutter/) + +Then, you can run the example using the following command: + +```bash +flutter create . +flutter run -d chrome +``` + +For some platforms, such as macOS, you may need to add internet permissions to the app. \ No newline at end of file diff --git a/packages/stream_feeds/example/analysis_options.yaml b/packages/stream_feeds/example/analysis_options.yaml new file mode 100644 index 00000000..f9b30346 --- /dev/null +++ b/packages/stream_feeds/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/packages/stream_feeds/example/lib/main.dart b/packages/stream_feeds/example/lib/main.dart new file mode 100644 index 00000000..7252ffa5 --- /dev/null +++ b/packages/stream_feeds/example/lib/main.dart @@ -0,0 +1,181 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_state_notifier/flutter_state_notifier.dart'; +import 'package:stream_feeds/stream_feeds.dart'; + +/// Get your own credentials from Stream. +/// For more detailed documentation and examples, visit: +/// https://getstream.io/activity-feeds/docs/flutter/ +const apiKey = ''; +const userId = ''; +const userToken = ''; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp(title: 'Stream Feeds Example', home: const MyHomePage()); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key}); + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + late StreamFeedsClient client; + late Future connectionFuture; + + @override + void initState() { + super.initState(); + client = StreamFeedsClient( + apiKey: apiKey, + user: User(id: userId), + tokenProvider: TokenProvider.static(UserToken(userToken)), + ); + connectionFuture = client.connect(); + } + + @override + void dispose() { + client.disconnect(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Stream Feeds Example')), + body: FutureBuilder( + future: connectionFuture, + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + return MyTimeLine(client: client); + default: + return const Center(child: CircularProgressIndicator()); + } + }, + ), + ); + } +} + +class MyTimeLine extends StatefulWidget { + const MyTimeLine({super.key, required this.client}); + final StreamFeedsClient client; + + @override + State createState() => _MyTimeLineState(); +} + +class _MyTimeLineState extends State { + late final Feed feed; + + @override + void initState() { + super.initState(); + feed = widget.client.feedFromId(FeedId.timeline(userId)); + feed.getOrCreate(); + } + + @override + void dispose() { + feed.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return StateNotifierBuilder( + stateNotifier: feed.notifier, + builder: (context, state, child) { + return ListView.separated( + itemCount: state.activities.length + 1, + separatorBuilder: (context, index) => const Divider(), + itemBuilder: (context, index) { + if (index == state.activities.length) { + if (state.canLoadMoreActivities) { + return TextButton( + onPressed: () { + feed.queryMoreActivities(); + }, + child: const Text('Load more'), + ); + } else { + return const Text('No more activities'); + } + } + + return ActivityItem(activity: state.activities[index]); + }, + ); + }, + ); + } +} + +class ActivityItem extends StatelessWidget { + const ActivityItem({super.key, required this.activity}); + + final ActivityData activity; + + @override + Widget build(BuildContext context) { + // Simple activity item with the activity text and an image if it has one + final userImage = activity.user.image; + final imageAttachment = activity.attachments.firstWhereOrNull( + (attachment) => attachment.imageUrl != null, + ); + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 50, + height: 50, + child: CircleAvatar( + backgroundImage: + userImage != null ? NetworkImage(userImage) : null, + child: Container( + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.3), + shape: BoxShape.circle, + ), + child: Center( + child: Text(activity.user.name?.characters.first ?? ''), + ), + ), + ), + ), + SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (imageAttachment != null) + SizedBox( + height: 200, + child: Image.network(imageAttachment.imageUrl!), + ), + Text(activity.text ?? ''), + ], + ), + ), + ], + ), + ); + } +} diff --git a/packages/stream_feeds/example/pubspec.yaml b/packages/stream_feeds/example/pubspec.yaml new file mode 100644 index 00000000..756a563c --- /dev/null +++ b/packages/stream_feeds/example/pubspec.yaml @@ -0,0 +1,23 @@ +name: example +description: "Example for the Stream Feeds SDK" +publish_to: 'none' # Remove this line if you wish to publish to pub.dev +version: 1.0.0+1 + +environment: + sdk: ^3.6.2 + +dependencies: + collection: ^1.18.0 + flutter: + sdk: flutter + flutter_state_notifier: ^1.0.0 + stream_feeds: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + +flutter: + uses-material-design: true \ No newline at end of file