Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ dev_dependencies:
flutter:
sdk: flutter
flutter_state_notifier: ^1.0.0
stream_feeds:
path: ../packages/stream_feeds
stream_feeds: ^0.1.0
3 changes: 3 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ command:
auto_route: ^10.0.0
cached_network_image: ^3.4.1
collection: ^1.18.0
chewie: ^1.11.3
dio: ^5.9.0
equatable: ^2.0.5
flutter_state_notifier: ^1.0.0
Expand All @@ -35,13 +36,15 @@ command:
http: ^1.1.0
intl: ">=0.18.1 <=0.21.0"
jiffy: ^6.3.2
photo_view: ^0.15.0
json_annotation: ^4.9.0
meta: ^1.9.1
retrofit: ^4.6.0
rxdart: ^0.28.0
shared_preferences: ^2.5.3
state_notifier: ^1.0.0
stream_core: ^0.1.0
video_player: ^2.10.0
uuid: ^4.5.1

# List of all the dev_dependencies used in the project.
Expand Down
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.16.0"
version: "1.17.0"
mustache_template:
dependency: transitive
description:
Expand Down
6 changes: 6 additions & 0 deletions sample_app/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
include: ../analysis_options.yaml

analyzer:
# TODO: not working if added on the root analysis file
exclude:
# exclude all the generated files
- lib/**/*.*.dart

linter:
rules:
cascade_invocations: false
Expand Down
10 changes: 6 additions & 4 deletions sample_app/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@ plugins {
android {
namespace = "io.getstream.feeds.flutter.sample"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973"

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
isCoreLibraryDesugaringEnabled = true
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "io.getstream.feeds.flutter.sample"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
Expand All @@ -42,3 +40,7 @@ android {
flutter {
source = "../.."
}

dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}
2 changes: 1 addition & 1 deletion sample_app/android/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pluginManagement {
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}

include(":app")
36 changes: 35 additions & 1 deletion sample_app/lib/navigation/app_router.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:injectable/injectable.dart';
import 'package:stream_feeds/stream_feeds.dart';

import '../screens/choose_user/choose_user_screen.dart';
import '../screens/home/home_screen.dart';

import '../screens/user_feed/user_feed_screen.dart';
import '../widgets/attachment_gallery/attachment_gallery.dart';
import '../widgets/attachment_gallery/attachment_metadata.dart';
import 'guards/auth_guard.dart';

part 'app_router.gr.dart';
Expand Down Expand Up @@ -41,6 +45,36 @@ class AppRouter extends RootStackRouter {
page: ChooseUserRoute.page,
keepHistory: false,
),
AutoRoute(
path: '/attachment_gallery',
page: AttachmentGalleryRoute.page,
fullscreenDialog: true,
guards: [_authGuard],
),
];
}
}

/// Shell route for attachment gallery
@RoutePage()
class AttachmentGalleryPage extends StatelessWidget {
const AttachmentGalleryPage({
super.key,
required this.attachments,
required this.metadata,
this.initialIndex = 0,
});

final List<Attachment> attachments;
final AttachmentMetadata metadata;
final int initialIndex;

@override
Widget build(BuildContext context) {
return AttachmentGallery(
attachments: attachments,
metadata: metadata,
initialIndex: initialIndex,
);
}
}
75 changes: 75 additions & 0 deletions sample_app/lib/navigation/app_router.gr.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion sample_app/lib/screens/user_feed/feed/user_feed_item.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:stream_feeds/stream_feeds.dart';

import '../../../navigation/app_router.dart';
import '../../../theme/extensions/theme_extensions.dart';
import '../../../utils/date_time_extensions.dart';
import '../../../widgets/action_button.dart';
import '../../../widgets/attachment_gallery/attachment_metadata.dart';
import '../../../widgets/attachments/attachments.dart';
import '../../../widgets/user_avatar.dart';

Expand Down Expand Up @@ -137,7 +140,19 @@ class _ActivityBody extends StatelessWidget {
AttachmentGrid(
attachments: attachments,
onAttachmentTap: (attachment) {
// TODO: Implement fullscreen attachment view
final initialIndex = attachments.indexOf(attachment);

context.pushRoute(
AttachmentGalleryRoute(
attachments: attachments,
initialIndex: initialIndex >= 0 ? initialIndex : 0,
metadata: AttachmentMetadata(
author: data.user,
createdAt: data.createdAt,
caption: data.text,
),
),
);
},
),
],
Expand Down
105 changes: 105 additions & 0 deletions sample_app/lib/widgets/attachment_gallery/attachment_gallery.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import 'package:stream_feeds/stream_feeds.dart';

import '../../theme/theme.dart';
import 'attachment_gallery_chrome.dart';
import 'attachment_gallery_item.dart';
import 'attachment_metadata.dart';

class AttachmentGallery extends StatefulWidget {
const AttachmentGallery({
super.key,
this.initialIndex = 0,
required this.attachments,
required this.metadata,
}) : assert(initialIndex >= 0, 'Initial index must be non-negative');

final int initialIndex;
final List<Attachment> attachments;
final AttachmentMetadata metadata;

@override
State<AttachmentGallery> createState() => _AttachmentGalleryState();
}

class _AttachmentGalleryState extends State<AttachmentGallery> {
late final PageController _pageController;
late final _currentPage = ValueNotifier(widget.initialIndex);

late final _isDisplayingDetail = ValueNotifier<bool>(true);
void switchDisplayingDetail() {
_isDisplayingDetail.value = !_isDisplayingDetail.value;
}

@override
void initState() {
super.initState();
_pageController = PageController(initialPage: _currentPage.value);
}

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

@override
Widget build(BuildContext context) {
return Scaffold(
body: ValueListenableBuilder(
valueListenable: _currentPage,
builder: (context, currentPage, child) {
return Stack(
children: [
if (child case final child?) child,
// Chrome overlay
ValueListenableBuilder<bool>(
valueListenable: _isDisplayingDetail,
builder: (context, isVisible, child) {
return AttachmentGalleryChrome(
isVisible: isVisible,
metadata: widget.metadata,
currentAttachment: widget.attachments[currentPage],
currentIndex: currentPage + 1,
totalCount: widget.attachments.length,
);
},
),
],
);
},
child: InkWell(
onTap: switchDisplayingDetail,
child: PageView.builder(
controller: _pageController,
itemCount: widget.attachments.length,
onPageChanged: (page) => _currentPage.value = page,
itemBuilder: (context, index) {
final attachment = widget.attachments[index];
return ValueListenableBuilder(
valueListenable: _isDisplayingDetail,
builder: (context, displayingDetail, child) {
final padding = MediaQuery.paddingOf(context);

return AnimatedContainer(
duration: kThemeAnimationDuration,
color: switch (displayingDetail) {
true => context.appColors.appBg,
false => AppColorTokens.black,
},
padding: EdgeInsetsDirectional.only(
top: padding.top + kToolbarHeight,
bottom: padding.bottom + kToolbarHeight,
),
child: child,
);
},
child: AttachmentGalleryItem(attachment: attachment),
);
},
),
),
),
);
}
}
Loading