mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 10:33:44 +02:00
Merge pull request #42 from Iconica-Development/3.0.0
feat: default styling and flow
This commit is contained in:
commit
423f4ce03a
22 changed files with 791 additions and 414 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
## 3.0.0
|
||||||
|
- Add default styling and default flow
|
||||||
|
|
||||||
## 2.3.1
|
## 2.3.1
|
||||||
|
|
||||||
- Updated readme.
|
- Updated readme.
|
||||||
|
|
|
@ -43,9 +43,9 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
);
|
);
|
||||||
|
|
||||||
var button = FloatingActionButton(
|
var button = FloatingActionButton(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: const Color(0xff71C6D1),
|
||||||
onPressed: () async => context.go(
|
onPressed: () async => context.push(
|
||||||
TimelineUserStoryRoutes.timelinePostCreation,
|
TimelineUserStoryRoutes.timelineCategorySelection,
|
||||||
),
|
),
|
||||||
shape: const CircleBorder(),
|
shape: const CircleBorder(),
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
|
@ -62,10 +62,17 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
?.call(context, timelineScreen, button) ??
|
?.call(context, timelineScreen, button) ??
|
||||||
Scaffold(
|
Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: const Color(0xff212121),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Iconinstagram',
|
config
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
.optionsBuilder(context)
|
||||||
|
.translations
|
||||||
|
.timeLineScreenTitle!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: timelineScreen,
|
body: timelineScreen,
|
||||||
|
@ -74,6 +81,51 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: TimelineUserStoryRoutes.timelineCategorySelection,
|
||||||
|
pageBuilder: (context, state) {
|
||||||
|
var timelineSelectionScreen = TimelineSelectionScreen(
|
||||||
|
options: config.optionsBuilder(context),
|
||||||
|
categories: config
|
||||||
|
.optionsBuilder(context)
|
||||||
|
.categoriesOptions
|
||||||
|
.categoriesBuilder!(context),
|
||||||
|
onCategorySelected: (category) async {
|
||||||
|
await context.push(
|
||||||
|
TimelineUserStoryRoutes.timelinepostCreation(category.title),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
var backButton = IconButton(
|
||||||
|
color: Colors.white,
|
||||||
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
|
onPressed: () => context.go(TimelineUserStoryRoutes.timelineHome),
|
||||||
|
);
|
||||||
|
|
||||||
|
return buildScreenWithoutTransition(
|
||||||
|
context: context,
|
||||||
|
state: state,
|
||||||
|
child: config.categorySelectionOpenPageBuilder
|
||||||
|
?.call(context, timelineSelectionScreen) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: backButton,
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postCreation!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelineSelectionScreen,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: TimelineUserStoryRoutes.timelineView,
|
path: TimelineUserStoryRoutes.timelineView,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
|
@ -103,10 +155,14 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
Scaffold(
|
Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: backButton,
|
leading: backButton,
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: const Color(0xff212121),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Category',
|
post.category ?? 'Category',
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: timelinePostWidget,
|
body: timelinePostWidget,
|
||||||
|
@ -117,6 +173,7 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: TimelineUserStoryRoutes.timelinePostCreation,
|
path: TimelineUserStoryRoutes.timelinePostCreation,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
|
var category = state.pathParameters['category'];
|
||||||
var timelinePostCreationWidget = TimelinePostCreationScreen(
|
var timelinePostCreationWidget = TimelinePostCreationScreen(
|
||||||
userId: config.userId,
|
userId: config.userId,
|
||||||
options: config.optionsBuilder(context),
|
options: config.optionsBuilder(context),
|
||||||
|
@ -137,11 +194,16 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
extra: post,
|
extra: post,
|
||||||
),
|
),
|
||||||
enablePostOverviewScreen: config.enablePostOverviewScreen,
|
enablePostOverviewScreen: config.enablePostOverviewScreen,
|
||||||
|
postCategory: category,
|
||||||
);
|
);
|
||||||
|
|
||||||
var backButton = IconButton(
|
var backButton = IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(
|
||||||
onPressed: () => context.go(TimelineUserStoryRoutes.timelineHome),
|
Icons.arrow_back_ios,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
context.go(TimelineUserStoryRoutes.timelineCategorySelection),
|
||||||
);
|
);
|
||||||
|
|
||||||
return buildScreenWithoutTransition(
|
return buildScreenWithoutTransition(
|
||||||
|
@ -151,12 +213,16 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
?.call(context, timelinePostCreationWidget, backButton) ??
|
?.call(context, timelinePostCreationWidget, backButton) ??
|
||||||
Scaffold(
|
Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: const Color(0xff212121),
|
||||||
title: Text(
|
|
||||||
config.optionsBuilder(context).translations.postCreation,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
leading: backButton,
|
leading: backButton,
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postCreation!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
body: timelinePostCreationWidget,
|
body: timelinePostCreationWidget,
|
||||||
),
|
),
|
||||||
|
@ -179,6 +245,13 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
var backButton = IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () async => context.pop(),
|
||||||
|
);
|
||||||
|
|
||||||
return buildScreenWithoutTransition(
|
return buildScreenWithoutTransition(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -187,7 +260,21 @@ List<GoRoute> getTimelineStoryRoutes({
|
||||||
context,
|
context,
|
||||||
timelinePostOverviewWidget,
|
timelinePostOverviewWidget,
|
||||||
) ??
|
) ??
|
||||||
timelinePostOverviewWidget,
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: backButton,
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postOverview!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelinePostOverviewWidget,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -44,23 +44,11 @@ Widget _timelineScreenRoute({
|
||||||
optionsBuilder: (context) => const TimelineOptions(),
|
optionsBuilder: (context) => const TimelineOptions(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Scaffold(
|
var timelineScreen = TimelineScreen(
|
||||||
appBar: AppBar(),
|
userId: config.userId,
|
||||||
floatingActionButton: FloatingActionButton(
|
onUserTap: (user) => config.onUserTap?.call(context, user),
|
||||||
onPressed: () async => Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => _postCreationScreenRoute(
|
|
||||||
configuration: config,
|
|
||||||
context: context,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
),
|
|
||||||
body: TimelineScreen(
|
|
||||||
service: config.service,
|
service: config.service,
|
||||||
options: config.optionsBuilder(context),
|
options: config.optionsBuilder(context),
|
||||||
userId: config.userId,
|
|
||||||
onPostTap: (post) async =>
|
onPostTap: (post) async =>
|
||||||
config.onPostTap?.call(context, post) ??
|
config.onPostTap?.call(context, post) ??
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
|
@ -72,12 +60,43 @@ Widget _timelineScreenRoute({
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onUserTap: (userId) {
|
|
||||||
config.onUserTap?.call(context, userId);
|
|
||||||
},
|
|
||||||
filterEnabled: config.filterEnabled,
|
filterEnabled: config.filterEnabled,
|
||||||
postWidgetBuilder: config.postWidgetBuilder,
|
postWidgetBuilder: config.postWidgetBuilder,
|
||||||
|
);
|
||||||
|
|
||||||
|
var button = FloatingActionButton(
|
||||||
|
backgroundColor: const Color(0xff71C6D1),
|
||||||
|
onPressed: () async => Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => _postCategorySelectionScreen(
|
||||||
|
configuration: config,
|
||||||
|
context: context,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return config.homeOpenPageBuilder?.call(context, timelineScreen, button) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.timeLineScreenTitle!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelineScreen,
|
||||||
|
floatingActionButton: button,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,15 +120,39 @@ Widget _postDetailScreenRoute({
|
||||||
optionsBuilder: (context) => const TimelineOptions(),
|
optionsBuilder: (context) => const TimelineOptions(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return TimelinePostScreen(
|
var timelinePostScreen = TimelinePostScreen(
|
||||||
userId: config.userId,
|
userId: config.userId,
|
||||||
service: config.service,
|
|
||||||
options: config.optionsBuilder(context),
|
options: config.optionsBuilder(context),
|
||||||
|
service: config.service,
|
||||||
post: post,
|
post: post,
|
||||||
onPostDelete: () async {
|
onPostDelete: () async =>
|
||||||
config.onPostDelete?.call(context, post) ??
|
config.onPostDelete?.call(context, post) ??
|
||||||
await config.service.postService.deletePost(post);
|
await config.service.postService.deletePost(post),
|
||||||
},
|
onUserTap: (user) => config.onUserTap?.call(context, user),
|
||||||
|
);
|
||||||
|
|
||||||
|
var backButton = IconButton(
|
||||||
|
color: Colors.white,
|
||||||
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return config.postViewOpenPageBuilder
|
||||||
|
?.call(context, timelinePostScreen, backButton) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: backButton,
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
post.category ?? 'Category',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelinePostScreen,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +163,7 @@ Widget _postDetailScreenRoute({
|
||||||
/// as parameters. If no configuration is provided, default values will be used.
|
/// as parameters. If no configuration is provided, default values will be used.
|
||||||
Widget _postCreationScreenRoute({
|
Widget _postCreationScreenRoute({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
|
required TimelineCategory category,
|
||||||
TimelineUserStoryConfiguration? configuration,
|
TimelineUserStoryConfiguration? configuration,
|
||||||
}) {
|
}) {
|
||||||
var config = configuration ??
|
var config = configuration ??
|
||||||
|
@ -131,19 +175,12 @@ Widget _postCreationScreenRoute({
|
||||||
optionsBuilder: (context) => const TimelineOptions(),
|
optionsBuilder: (context) => const TimelineOptions(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Scaffold(
|
var timelinePostCreationScreen = TimelinePostCreationScreen(
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
config.optionsBuilder(context).translations.postCreation,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: TimelinePostCreationScreen(
|
|
||||||
userId: config.userId,
|
userId: config.userId,
|
||||||
service: config.service,
|
|
||||||
options: config.optionsBuilder(context),
|
options: config.optionsBuilder(context),
|
||||||
|
service: config.service,
|
||||||
onPostCreated: (post) async {
|
onPostCreated: (post) async {
|
||||||
await config.service.postService.createPost(post);
|
var newPost = await config.service.postService.createPost(post);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
if (config.afterPostCreationGoHome) {
|
if (config.afterPostCreationGoHome) {
|
||||||
await Navigator.pushReplacement(
|
await Navigator.pushReplacement(
|
||||||
|
@ -156,21 +193,20 @@ Widget _postCreationScreenRoute({
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await Navigator.pushReplacement(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => _postDetailScreenRoute(
|
builder: (context) => _postOverviewScreenRoute(
|
||||||
configuration: config,
|
configuration: config,
|
||||||
context: context,
|
context: context,
|
||||||
post: post,
|
post: newPost,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPostOverview: (post) async {
|
onPostOverview: (post) async => Navigator.of(context).push(
|
||||||
await Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => _postOverviewScreenRoute(
|
builder: (context) => _postOverviewScreenRoute(
|
||||||
configuration: config,
|
configuration: config,
|
||||||
|
@ -178,10 +214,35 @@ Widget _postCreationScreenRoute({
|
||||||
post: post,
|
post: post,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
enablePostOverviewScreen: config.enablePostOverviewScreen,
|
|
||||||
),
|
),
|
||||||
|
enablePostOverviewScreen: config.enablePostOverviewScreen,
|
||||||
|
postCategory: category.title,
|
||||||
|
);
|
||||||
|
|
||||||
|
var backButton = IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return config.postCreationOpenPageBuilder
|
||||||
|
?.call(context, timelinePostCreationScreen, backButton) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
leading: backButton,
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postCreation!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelinePostCreationScreen,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,21 +266,109 @@ Widget _postOverviewScreenRoute({
|
||||||
optionsBuilder: (context) => const TimelineOptions(),
|
optionsBuilder: (context) => const TimelineOptions(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return TimelinePostOverviewScreen(
|
var timelinePostOverviewWidget = TimelinePostOverviewScreen(
|
||||||
timelinePost: post,
|
|
||||||
options: config.optionsBuilder(context),
|
options: config.optionsBuilder(context),
|
||||||
service: config.service,
|
service: config.service,
|
||||||
|
timelinePost: post,
|
||||||
onPostSubmit: (post) async {
|
onPostSubmit: (post) async {
|
||||||
await config.service.postService.createPost(post);
|
await config.service.postService.createPost(post);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await Navigator.pushReplacement(
|
await Navigator.of(context).pushAndRemoveUntil(
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_timelineScreenRoute(configuration: config, context: context),
|
_timelineScreenRoute(configuration: config, context: context),
|
||||||
),
|
),
|
||||||
|
(route) => false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isOverviewScreen: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
var backButton = IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () async => Navigator.of(context).pop(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return config.postOverviewOpenPageBuilder?.call(
|
||||||
|
context,
|
||||||
|
timelinePostOverviewWidget,
|
||||||
|
) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: backButton,
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postOverview!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelinePostOverviewWidget,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _postCategorySelectionScreen({
|
||||||
|
required BuildContext context,
|
||||||
|
TimelineUserStoryConfiguration? configuration,
|
||||||
|
}) {
|
||||||
|
var config = configuration ??
|
||||||
|
TimelineUserStoryConfiguration(
|
||||||
|
userId: 'test_user',
|
||||||
|
service: TimelineService(
|
||||||
|
postService: LocalTimelinePostService(),
|
||||||
|
),
|
||||||
|
optionsBuilder: (context) => const TimelineOptions(),
|
||||||
|
);
|
||||||
|
|
||||||
|
var timelineSelectionScreen = TimelineSelectionScreen(
|
||||||
|
options: config.optionsBuilder(context),
|
||||||
|
categories: config
|
||||||
|
.optionsBuilder(context)
|
||||||
|
.categoriesOptions
|
||||||
|
.categoriesBuilder!(context),
|
||||||
|
onCategorySelected: (category) async {
|
||||||
|
await Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => _postCreationScreenRoute(
|
||||||
|
configuration: config,
|
||||||
|
context: context,
|
||||||
|
category: category,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
var backButton = IconButton(
|
||||||
|
color: Colors.white,
|
||||||
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return config.categorySelectionOpenPageBuilder
|
||||||
|
?.call(context, timelineSelectionScreen) ??
|
||||||
|
Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: backButton,
|
||||||
|
backgroundColor: const Color(0xff212121),
|
||||||
|
title: Text(
|
||||||
|
config.optionsBuilder(context).translations.postCreation!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xff71C6D1),
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: timelineSelectionScreen,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,8 @@ class TimelineUserStoryConfiguration {
|
||||||
this.filterEnabled = false,
|
this.filterEnabled = false,
|
||||||
this.postWidgetBuilder,
|
this.postWidgetBuilder,
|
||||||
this.afterPostCreationGoHome = false,
|
this.afterPostCreationGoHome = false,
|
||||||
this.enablePostOverviewScreen = false,
|
this.enablePostOverviewScreen = true,
|
||||||
|
this.categorySelectionOpenPageBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The ID of the user associated with this user story configuration.
|
/// The ID of the user associated with this user story configuration.
|
||||||
|
@ -132,4 +133,11 @@ class TimelineUserStoryConfiguration {
|
||||||
/// Boolean to enable redirect to home after post creation.
|
/// Boolean to enable redirect to home after post creation.
|
||||||
/// If false, it will redirect to created post screen
|
/// If false, it will redirect to created post screen
|
||||||
final bool afterPostCreationGoHome;
|
final bool afterPostCreationGoHome;
|
||||||
|
|
||||||
|
/// Open page builder function for the category selection page. This function
|
||||||
|
/// accepts a [BuildContext] and a child widget.
|
||||||
|
final Function(
|
||||||
|
BuildContext context,
|
||||||
|
Widget child,
|
||||||
|
)? categorySelectionOpenPageBuilder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ mixin TimelineUserStoryRoutes {
|
||||||
static const String timelineHome = '/timeline';
|
static const String timelineHome = '/timeline';
|
||||||
static const String timelineView = '/timeline-view/:post';
|
static const String timelineView = '/timeline-view/:post';
|
||||||
static String timelineViewPath(String postId) => '/timeline-view/$postId';
|
static String timelineViewPath(String postId) => '/timeline-view/$postId';
|
||||||
static const String timelinePostCreation = '/timeline-post-creation';
|
static String timelinepostCreation(String category) =>
|
||||||
|
'/timeline-post-creation/$category';
|
||||||
|
|
||||||
|
static const String timelinePostCreation =
|
||||||
|
'/timeline-post-creation/:category';
|
||||||
static String timelinePostOverview = '/timeline-post-overview';
|
static String timelinePostOverview = '/timeline-post-overview';
|
||||||
|
static String timelineCategorySelection = '/timeline-category-selection';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
name: flutter_timeline
|
name: flutter_timeline
|
||||||
description: Visual elements and interface combined into one package
|
description: Visual elements and interface combined into one package
|
||||||
version: 2.3.1
|
version: 3.0.0
|
||||||
|
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_timeline
|
url: https://github.com/Iconica-Development/flutter_timeline
|
||||||
path: packages/flutter_timeline_view
|
path: packages/flutter_timeline_view
|
||||||
ref: 2.3.1
|
ref: 3.0.0
|
||||||
|
|
||||||
flutter_timeline_interface:
|
flutter_timeline_interface:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_timeline
|
url: https://github.com/Iconica-Development/flutter_timeline
|
||||||
path: packages/flutter_timeline_interface
|
path: packages/flutter_timeline_interface
|
||||||
ref: 2.3.1
|
ref: 3.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
name: flutter_timeline_firebase
|
name: flutter_timeline_firebase
|
||||||
description: Implementation of the Flutter Timeline interface for Firebase.
|
description: Implementation of the Flutter Timeline interface for Firebase.
|
||||||
version: 2.3.1
|
version: 3.0.0
|
||||||
|
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_timeline
|
url: https://github.com/Iconica-Development/flutter_timeline
|
||||||
path: packages/flutter_timeline_interface
|
path: packages/flutter_timeline_interface
|
||||||
ref: 2.3.1
|
ref: 3.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
name: flutter_timeline_interface
|
name: flutter_timeline_interface
|
||||||
description: Interface for the service of the Flutter Timeline component
|
description: Interface for the service of the Flutter Timeline component
|
||||||
version: 2.3.1
|
version: 3.0.0
|
||||||
|
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import 'package:intl/intl.dart';
|
||||||
class TimelineOptions {
|
class TimelineOptions {
|
||||||
const TimelineOptions({
|
const TimelineOptions({
|
||||||
this.theme = const TimelineTheme(),
|
this.theme = const TimelineTheme(),
|
||||||
this.translations = const TimelineTranslations.empty(),
|
this.translations = const TimelineTranslations(),
|
||||||
this.imagePickerConfig = const ImagePickerConfig(),
|
this.imagePickerConfig = const ImagePickerConfig(),
|
||||||
this.imagePickerTheme = const ImagePickerTheme(),
|
this.imagePickerTheme = const ImagePickerTheme(),
|
||||||
this.timelinePostHeight,
|
this.timelinePostHeight,
|
||||||
|
@ -37,7 +37,8 @@ class TimelineOptions {
|
||||||
this.userAvatarBuilder,
|
this.userAvatarBuilder,
|
||||||
this.anonymousAvatarBuilder,
|
this.anonymousAvatarBuilder,
|
||||||
this.nameBuilder,
|
this.nameBuilder,
|
||||||
this.padding = const EdgeInsets.symmetric(vertical: 12.0),
|
this.padding =
|
||||||
|
const EdgeInsets.only(left: 12.0, top: 24.0, right: 12.0, bottom: 12.0),
|
||||||
this.iconSize = 26,
|
this.iconSize = 26,
|
||||||
this.postWidgetHeight,
|
this.postWidgetHeight,
|
||||||
this.postPadding =
|
this.postPadding =
|
||||||
|
@ -49,6 +50,10 @@ class TimelineOptions {
|
||||||
this.maxTitleLength,
|
this.maxTitleLength,
|
||||||
this.minContentLength,
|
this.minContentLength,
|
||||||
this.maxContentLength,
|
this.maxContentLength,
|
||||||
|
this.categorySelectorButtonBuilder,
|
||||||
|
this.postOverviewButtonBuilder,
|
||||||
|
this.titleInputDecoration,
|
||||||
|
this.contentInputDecoration,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Theming options for the timeline
|
/// Theming options for the timeline
|
||||||
|
@ -142,11 +147,69 @@ class TimelineOptions {
|
||||||
|
|
||||||
/// Maximum length of the post content
|
/// Maximum length of the post content
|
||||||
final int? maxContentLength;
|
final int? maxContentLength;
|
||||||
|
|
||||||
|
/// Builder for the category selector button
|
||||||
|
/// on the timeline category selection screen
|
||||||
|
final Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
Function() onPressed,
|
||||||
|
String text,
|
||||||
|
)? categorySelectorButtonBuilder;
|
||||||
|
|
||||||
|
/// Builder for the post overview button
|
||||||
|
/// on the timeline post overview screen
|
||||||
|
final Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
Function() onPressed,
|
||||||
|
String text,
|
||||||
|
)? postOverviewButtonBuilder;
|
||||||
|
|
||||||
|
/// inputdecoration for the title textfield
|
||||||
|
final InputDecoration? titleInputDecoration;
|
||||||
|
|
||||||
|
/// inputdecoration for the content textfield
|
||||||
|
final InputDecoration? contentInputDecoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<TimelineCategory> _getDefaultCategories(context) => [
|
||||||
|
const TimelineCategory(
|
||||||
|
key: null,
|
||||||
|
title: 'All',
|
||||||
|
icon: Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.apps,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TimelineCategory(
|
||||||
|
key: 'Category',
|
||||||
|
title: 'Category',
|
||||||
|
icon: Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.category,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TimelineCategory(
|
||||||
|
key: 'Category with two lines',
|
||||||
|
title: 'Category with two lines',
|
||||||
|
icon: Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.category,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
class CategoriesOptions {
|
class CategoriesOptions {
|
||||||
const CategoriesOptions({
|
const CategoriesOptions({
|
||||||
this.categoriesBuilder,
|
this.categoriesBuilder = _getDefaultCategories,
|
||||||
this.categoryButtonBuilder,
|
this.categoryButtonBuilder,
|
||||||
this.categorySelectorHorizontalPadding,
|
this.categorySelectorHorizontalPadding,
|
||||||
});
|
});
|
||||||
|
@ -157,12 +220,14 @@ class CategoriesOptions {
|
||||||
categoriesBuilder;
|
categoriesBuilder;
|
||||||
|
|
||||||
/// Abilty to override the standard category selector
|
/// Abilty to override the standard category selector
|
||||||
final Widget Function({
|
final Widget Function(
|
||||||
required String? categoryKey,
|
String? categoryKey,
|
||||||
required String categoryName,
|
String categoryName,
|
||||||
required Function onTap,
|
Function() onTap,
|
||||||
required bool selected,
|
// ignore: avoid_positional_boolean_parameters
|
||||||
})? categoryButtonBuilder;
|
bool selected,
|
||||||
|
bool isOnTop,
|
||||||
|
)? categoryButtonBuilder;
|
||||||
|
|
||||||
/// Overides the standard horizontal padding of the whole category selector.
|
/// Overides the standard horizontal padding of the whole category selector.
|
||||||
final double? categorySelectorHorizontalPadding;
|
final double? categorySelectorHorizontalPadding;
|
||||||
|
|
|
@ -7,108 +7,78 @@ import 'package:flutter/material.dart';
|
||||||
@immutable
|
@immutable
|
||||||
class TimelineTranslations {
|
class TimelineTranslations {
|
||||||
const TimelineTranslations({
|
const TimelineTranslations({
|
||||||
required this.anonymousUser,
|
this.anonymousUser = 'Anonymous user',
|
||||||
required this.noPosts,
|
this.noPosts = 'No posts yet',
|
||||||
required this.noPostsWithFilter,
|
this.noPostsWithFilter = 'No posts with this filter',
|
||||||
required this.title,
|
this.title = 'Title',
|
||||||
required this.titleHintText,
|
this.titleHintText = 'Title...',
|
||||||
required this.content,
|
this.content = 'Content',
|
||||||
required this.contentHintText,
|
this.contentHintText = 'Content...',
|
||||||
required this.contentDescription,
|
this.contentDescription = 'What do you want to share?',
|
||||||
required this.uploadImage,
|
this.uploadImage = 'Upload image',
|
||||||
required this.uploadImageDescription,
|
this.uploadImageDescription = 'Upload an image to your message (optional)',
|
||||||
required this.allowComments,
|
this.allowComments = 'Are people allowed to comment?',
|
||||||
required this.allowCommentsDescription,
|
this.allowCommentsDescription =
|
||||||
required this.commentsTitleOnPost,
|
'Indicate whether people are allowed to respond',
|
||||||
required this.checkPost,
|
this.commentsTitleOnPost = 'Comments',
|
||||||
required this.deletePost,
|
this.checkPost = 'Check post overview',
|
||||||
required this.deleteReaction,
|
this.deletePost = 'Delete post',
|
||||||
required this.viewPost,
|
this.deleteReaction = 'Delete Reaction',
|
||||||
required this.likesTitle,
|
this.viewPost = 'View post',
|
||||||
required this.commentsTitle,
|
this.likesTitle = 'Likes',
|
||||||
required this.firstComment,
|
this.commentsTitle = 'Are people allowed to comment?',
|
||||||
required this.writeComment,
|
this.firstComment = 'Be the first to comment',
|
||||||
required this.postAt,
|
this.writeComment = 'Write your comment here...',
|
||||||
required this.postLoadingError,
|
this.postAt = 'at',
|
||||||
required this.timelineSelectionDescription,
|
this.postLoadingError = 'Something went wrong while loading the post',
|
||||||
required this.searchHint,
|
this.timelineSelectionDescription = 'Choose a category',
|
||||||
required this.postOverview,
|
this.searchHint = 'Search...',
|
||||||
required this.postIn,
|
this.postOverview = 'Post Overview',
|
||||||
required this.postCreation,
|
this.postIn = 'Post in',
|
||||||
required this.yes,
|
this.postCreation = 'add post',
|
||||||
required this.no,
|
this.yes = 'Yes',
|
||||||
|
this.no = 'No',
|
||||||
|
this.timeLineScreenTitle = 'iconinstagram',
|
||||||
});
|
});
|
||||||
|
|
||||||
const TimelineTranslations.empty()
|
final String? noPosts;
|
||||||
: anonymousUser = 'Anonymous user',
|
final String? noPostsWithFilter;
|
||||||
noPosts = 'No posts yet',
|
final String? anonymousUser;
|
||||||
noPostsWithFilter = 'No posts with this filter',
|
|
||||||
title = 'Title',
|
|
||||||
content = 'Content',
|
|
||||||
contentDescription = 'What do you want to share?',
|
|
||||||
uploadImage = 'Upload image',
|
|
||||||
uploadImageDescription = 'Upload an image to your message (optional)',
|
|
||||||
allowComments = 'Are people allowed to comment?',
|
|
||||||
allowCommentsDescription =
|
|
||||||
'Indicate whether people are allowed to respond',
|
|
||||||
commentsTitleOnPost = 'Comments',
|
|
||||||
checkPost = 'Check post overview',
|
|
||||||
deletePost = 'Delete post',
|
|
||||||
deleteReaction = 'Delete Reaction',
|
|
||||||
viewPost = 'View post',
|
|
||||||
likesTitle = 'Likes',
|
|
||||||
commentsTitle = 'Are people allowed to comment?',
|
|
||||||
firstComment = 'Be the first to comment',
|
|
||||||
writeComment = 'Write your comment here...',
|
|
||||||
postAt = 'at',
|
|
||||||
postLoadingError = 'Something went wrong while loading the post',
|
|
||||||
timelineSelectionDescription = 'Choose a category',
|
|
||||||
searchHint = 'Search...',
|
|
||||||
postOverview = 'Post Overview',
|
|
||||||
postIn = 'Post in',
|
|
||||||
postCreation = 'Create Post',
|
|
||||||
titleHintText = 'Title...',
|
|
||||||
contentHintText = 'Context...',
|
|
||||||
yes = 'Yes',
|
|
||||||
no = 'No';
|
|
||||||
|
|
||||||
final String noPosts;
|
final String? title;
|
||||||
final String noPostsWithFilter;
|
final String? content;
|
||||||
final String anonymousUser;
|
final String? contentDescription;
|
||||||
|
final String? uploadImage;
|
||||||
|
final String? uploadImageDescription;
|
||||||
|
final String? allowComments;
|
||||||
|
final String? allowCommentsDescription;
|
||||||
|
final String? checkPost;
|
||||||
|
final String? postAt;
|
||||||
|
|
||||||
final String title;
|
final String? titleHintText;
|
||||||
final String content;
|
final String? contentHintText;
|
||||||
final String contentDescription;
|
|
||||||
final String uploadImage;
|
|
||||||
final String uploadImageDescription;
|
|
||||||
final String allowComments;
|
|
||||||
final String allowCommentsDescription;
|
|
||||||
final String checkPost;
|
|
||||||
final String postAt;
|
|
||||||
|
|
||||||
final String titleHintText;
|
final String? deletePost;
|
||||||
final String contentHintText;
|
final String? deleteReaction;
|
||||||
|
final String? viewPost;
|
||||||
|
final String? likesTitle;
|
||||||
|
final String? commentsTitle;
|
||||||
|
final String? commentsTitleOnPost;
|
||||||
|
final String? writeComment;
|
||||||
|
final String? firstComment;
|
||||||
|
final String? postLoadingError;
|
||||||
|
|
||||||
final String deletePost;
|
final String? timelineSelectionDescription;
|
||||||
final String deleteReaction;
|
|
||||||
final String viewPost;
|
|
||||||
final String likesTitle;
|
|
||||||
final String commentsTitle;
|
|
||||||
final String commentsTitleOnPost;
|
|
||||||
final String writeComment;
|
|
||||||
final String firstComment;
|
|
||||||
final String postLoadingError;
|
|
||||||
|
|
||||||
final String timelineSelectionDescription;
|
final String? searchHint;
|
||||||
|
|
||||||
final String searchHint;
|
final String? postOverview;
|
||||||
|
final String? postIn;
|
||||||
|
final String? postCreation;
|
||||||
|
|
||||||
final String postOverview;
|
final String? yes;
|
||||||
final String postIn;
|
final String? no;
|
||||||
final String postCreation;
|
final String? timeLineScreenTitle;
|
||||||
|
|
||||||
final String yes;
|
|
||||||
final String no;
|
|
||||||
|
|
||||||
TimelineTranslations copyWith({
|
TimelineTranslations copyWith({
|
||||||
String? noPosts,
|
String? noPosts,
|
||||||
|
@ -141,6 +111,7 @@ class TimelineTranslations {
|
||||||
String? contentHintText,
|
String? contentHintText,
|
||||||
String? yes,
|
String? yes,
|
||||||
String? no,
|
String? no,
|
||||||
|
String? timeLineScreenTitle,
|
||||||
}) =>
|
}) =>
|
||||||
TimelineTranslations(
|
TimelineTranslations(
|
||||||
noPosts: noPosts ?? this.noPosts,
|
noPosts: noPosts ?? this.noPosts,
|
||||||
|
@ -176,5 +147,6 @@ class TimelineTranslations {
|
||||||
contentHintText: contentHintText ?? this.contentHintText,
|
contentHintText: contentHintText ?? this.contentHintText,
|
||||||
yes: yes ?? this.yes,
|
yes: yes ?? this.yes,
|
||||||
no: no ?? this.no,
|
no: no ?? this.no,
|
||||||
|
timeLineScreenTitle: timeLineScreenTitle ?? this.timeLineScreenTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,12 +124,15 @@ class _TimelinePostCreationScreenState
|
||||||
padding: widget.options.padding,
|
padding: widget.options.padding,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.title,
|
widget.options.translations.title!,
|
||||||
style: theme.textTheme.titleMedium,
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
widget.options.textInputBuilder?.call(
|
widget.options.textInputBuilder?.call(
|
||||||
titleController,
|
titleController,
|
||||||
|
@ -138,44 +141,49 @@ class _TimelinePostCreationScreenState
|
||||||
) ??
|
) ??
|
||||||
TextField(
|
TextField(
|
||||||
controller: titleController,
|
controller: titleController,
|
||||||
decoration: InputDecoration(
|
decoration: widget.options.contentInputDecoration ??
|
||||||
|
InputDecoration(
|
||||||
hintText: widget.options.translations.titleHintText,
|
hintText: widget.options.translations.titleHintText,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.content,
|
widget.options.translations.content!,
|
||||||
style: theme.textTheme.titleMedium,
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.contentDescription,
|
widget.options.translations.contentDescription!,
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
// input field for the content
|
// input field for the content
|
||||||
SizedBox(
|
TextField(
|
||||||
height: 100,
|
|
||||||
child: TextField(
|
|
||||||
controller: contentController,
|
controller: contentController,
|
||||||
textCapitalization: TextCapitalization.sentences,
|
textCapitalization: TextCapitalization.sentences,
|
||||||
expands: true,
|
expands: false,
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
minLines: null,
|
minLines: null,
|
||||||
decoration: InputDecoration(
|
decoration: widget.options.contentInputDecoration ??
|
||||||
|
InputDecoration(
|
||||||
hintText: widget.options.translations.contentHintText,
|
hintText: widget.options.translations.contentHintText,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
// input field for the content
|
// input field for the content
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.uploadImage,
|
widget.options.translations.uploadImage!,
|
||||||
style: theme.textTheme.titleMedium,
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.uploadImageDescription,
|
widget.options.translations.uploadImageDescription!,
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
// image picker field
|
// image picker field
|
||||||
|
@ -262,17 +270,21 @@ class _TimelinePostCreationScreenState
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.commentsTitle,
|
widget.options.translations.commentsTitle!,
|
||||||
style: theme.textTheme.titleMedium,
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.allowCommentsDescription,
|
widget.options.translations.allowCommentsDescription!,
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Checkbox(
|
Checkbox(
|
||||||
|
activeColor: const Color(0xff71C6D1),
|
||||||
value: allowComments,
|
value: allowComments,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -280,8 +292,9 @@ class _TimelinePostCreationScreenState
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Text(widget.options.translations.yes),
|
Text(widget.options.translations.yes!),
|
||||||
Checkbox(
|
Checkbox(
|
||||||
|
activeColor: const Color(0xff71C6D1),
|
||||||
value: !allowComments,
|
value: !allowComments,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -289,9 +302,10 @@ class _TimelinePostCreationScreenState
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Text(widget.options.translations.no),
|
Text(widget.options.translations.no!),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 120),
|
||||||
|
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
|
@ -299,10 +313,14 @@ class _TimelinePostCreationScreenState
|
||||||
? widget.options.buttonBuilder!(
|
? widget.options.buttonBuilder!(
|
||||||
context,
|
context,
|
||||||
onPostCreated,
|
onPostCreated,
|
||||||
widget.options.translations.checkPost,
|
widget.options.translations.checkPost!,
|
||||||
enabled: editingDone,
|
enabled: editingDone,
|
||||||
)
|
)
|
||||||
: ElevatedButton(
|
: ElevatedButton(
|
||||||
|
style: const ButtonStyle(
|
||||||
|
backgroundColor:
|
||||||
|
MaterialStatePropertyAll(Color(0xff71C6D1)),
|
||||||
|
),
|
||||||
onPressed: editingDone
|
onPressed: editingDone
|
||||||
? () async {
|
? () async {
|
||||||
await onPostCreated();
|
await onPostCreated();
|
||||||
|
@ -310,11 +328,18 @@ class _TimelinePostCreationScreenState
|
||||||
.fetchPosts(null);
|
.fetchPosts(null);
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.enablePostOverviewScreen
|
widget.enablePostOverviewScreen
|
||||||
? widget.options.translations.checkPost
|
? widget.options.translations.checkPost!
|
||||||
: widget.options.translations.postCreation,
|
: widget.options.translations.postCreation!,
|
||||||
style: theme.textTheme.bodyMedium,
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,24 +10,18 @@ class TimelinePostOverviewScreen extends StatelessWidget {
|
||||||
required this.options,
|
required this.options,
|
||||||
required this.service,
|
required this.service,
|
||||||
required this.onPostSubmit,
|
required this.onPostSubmit,
|
||||||
|
this.isOverviewScreen,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final TimelinePost timelinePost;
|
final TimelinePost timelinePost;
|
||||||
final TimelineOptions options;
|
final TimelineOptions options;
|
||||||
final TimelineService service;
|
final TimelineService service;
|
||||||
final void Function(TimelinePost) onPostSubmit;
|
final void Function(TimelinePost) onPostSubmit;
|
||||||
|
final bool? isOverviewScreen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Column(
|
||||||
appBar: AppBar(
|
|
||||||
backgroundColor: Colors.black,
|
|
||||||
title: Text(
|
|
||||||
options.translations.postOverview,
|
|
||||||
style: TextStyle(color: Theme.of(context).primaryColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: TimelinePostScreen(
|
child: TimelinePostScreen(
|
||||||
|
@ -36,21 +30,39 @@ class TimelinePostOverviewScreen extends StatelessWidget {
|
||||||
post: timelinePost,
|
post: timelinePost,
|
||||||
onPostDelete: () async {},
|
onPostDelete: () async {},
|
||||||
service: service,
|
service: service,
|
||||||
|
isOverviewScreen: isOverviewScreen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
options.postOverviewButtonBuilder?.call(
|
||||||
|
context,
|
||||||
|
() {
|
||||||
|
onPostSubmit(timelinePost);
|
||||||
|
},
|
||||||
|
'${options.translations.postIn} ${timelinePost.category}',
|
||||||
|
) ??
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30.0),
|
padding: const EdgeInsets.only(bottom: 30.0),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
|
style: const ButtonStyle(
|
||||||
|
backgroundColor: MaterialStatePropertyAll(Color(0xff71C6D1)),
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
onPostSubmit(timelinePost);
|
onPostSubmit(timelinePost);
|
||||||
},
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${options.translations.postIn} ${timelinePost.category}',
|
'${options.translations.postIn} ${timelinePost.category}',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ class TimelinePostScreen extends StatelessWidget {
|
||||||
required this.options,
|
required this.options,
|
||||||
required this.post,
|
required this.post,
|
||||||
required this.onPostDelete,
|
required this.onPostDelete,
|
||||||
|
this.isOverviewScreen = false,
|
||||||
this.onUserTap,
|
this.onUserTap,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
@ -43,6 +44,8 @@ class TimelinePostScreen extends StatelessWidget {
|
||||||
|
|
||||||
final VoidCallback onPostDelete;
|
final VoidCallback onPostDelete;
|
||||||
|
|
||||||
|
final bool? isOverviewScreen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
body: _TimelinePostScreen(
|
body: _TimelinePostScreen(
|
||||||
|
@ -52,6 +55,7 @@ class TimelinePostScreen extends StatelessWidget {
|
||||||
post: post,
|
post: post,
|
||||||
onPostDelete: onPostDelete,
|
onPostDelete: onPostDelete,
|
||||||
onUserTap: onUserTap,
|
onUserTap: onUserTap,
|
||||||
|
isOverviewScreen: isOverviewScreen,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +68,7 @@ class _TimelinePostScreen extends StatefulWidget {
|
||||||
required this.post,
|
required this.post,
|
||||||
required this.onPostDelete,
|
required this.onPostDelete,
|
||||||
this.onUserTap,
|
this.onUserTap,
|
||||||
|
this.isOverviewScreen,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String userId;
|
final String userId;
|
||||||
|
@ -78,6 +83,8 @@ class _TimelinePostScreen extends StatefulWidget {
|
||||||
|
|
||||||
final VoidCallback onPostDelete;
|
final VoidCallback onPostDelete;
|
||||||
|
|
||||||
|
final bool? isOverviewScreen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_TimelinePostScreen> createState() => _TimelinePostScreenState();
|
State<_TimelinePostScreen> createState() => _TimelinePostScreenState();
|
||||||
}
|
}
|
||||||
|
@ -145,7 +152,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
if (this.post == null) {
|
if (this.post == null) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.options.translations.postLoadingError,
|
widget.options.translations.postLoadingError!,
|
||||||
style: widget.options.theme.textStyles.errorTextStyle,
|
style: widget.options.theme.textStyles.errorTextStyle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -214,7 +221,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
widget.options.nameBuilder
|
widget.options.nameBuilder
|
||||||
?.call(post.creator) ??
|
?.call(post.creator) ??
|
||||||
post.creator?.fullName ??
|
post.creator?.fullName ??
|
||||||
widget.options.translations.anonymousUser,
|
widget.options.translations.anonymousUser!,
|
||||||
style: widget.options.theme.textStyles
|
style: widget.options.theme.textStyles
|
||||||
.postCreatorTitleStyle ??
|
.postCreatorTitleStyle ??
|
||||||
theme.textTheme.titleMedium,
|
theme.textTheme.titleMedium,
|
||||||
|
@ -234,7 +241,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.deletePost,
|
widget.options.translations.deletePost!,
|
||||||
style: widget.options.theme.textStyles
|
style: widget.options.theme.textStyles
|
||||||
.deletePostStyle ??
|
.deletePostStyle ??
|
||||||
theme.textTheme.bodyMedium,
|
theme.textTheme.bodyMedium,
|
||||||
|
@ -257,8 +264,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// image of the post
|
// image of the posts
|
||||||
if (post.imageUrl != null) ...[
|
if (post.imageUrl != null || post.image != null) ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
@ -293,6 +300,12 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
false;
|
false;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
: post.image != null
|
||||||
|
? Image.memory(
|
||||||
|
width: double.infinity,
|
||||||
|
post.image!,
|
||||||
|
fit: BoxFit.fitHeight,
|
||||||
|
)
|
||||||
: CachedNetworkImage(
|
: CachedNetworkImage(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
imageUrl: post.imageUrl!,
|
imageUrl: post.imageUrl!,
|
||||||
|
@ -320,9 +333,11 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: widget.options.theme.likedIcon ??
|
child: widget.options.theme.likedIcon ??
|
||||||
Icon(
|
Icon(
|
||||||
Icons.thumb_up_rounded,
|
widget.post.likedBy
|
||||||
color: widget.options.theme.iconColor,
|
?.contains(widget.userId) ??
|
||||||
size: widget.options.iconSize,
|
false
|
||||||
|
? Icons.favorite_rounded
|
||||||
|
: Icons.favorite_outline_outlined,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -340,8 +355,11 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: widget.options.theme.likeIcon ??
|
child: widget.options.theme.likeIcon ??
|
||||||
Icon(
|
Icon(
|
||||||
Icons.thumb_up_alt_outlined,
|
widget.post.likedBy
|
||||||
color: widget.options.theme.iconColor,
|
?.contains(widget.userId) ??
|
||||||
|
false
|
||||||
|
? Icons.favorite_rounded
|
||||||
|
: Icons.favorite_outline_outlined,
|
||||||
size: widget.options.iconSize,
|
size: widget.options.iconSize,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -423,7 +441,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (post.reactionEnabled) ...[
|
if (post.reactionEnabled) ...[
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.commentsTitleOnPost,
|
widget.options.translations.commentsTitleOnPost!,
|
||||||
style: theme.textTheme.titleMedium,
|
style: theme.textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
for (var reaction
|
for (var reaction
|
||||||
|
@ -451,7 +469,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'delete',
|
value: 'delete',
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.options.translations.deleteReaction,
|
widget.options.translations.deleteReaction!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -505,7 +523,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
?.call(post.creator) ??
|
?.call(post.creator) ??
|
||||||
reaction.creator?.fullName ??
|
reaction.creator?.fullName ??
|
||||||
widget.options.translations
|
widget.options.translations
|
||||||
.anonymousUser,
|
.anonymousUser!,
|
||||||
style: theme.textTheme.titleSmall,
|
style: theme.textTheme.titleSmall,
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -547,7 +565,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
if (post.reactions?.isEmpty ?? true) ...[
|
if (post.reactions?.isEmpty ?? true) ...[
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.firstComment,
|
widget.options.translations.firstComment!,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 120),
|
const SizedBox(height: 120),
|
||||||
|
@ -557,7 +575,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (post.reactionEnabled)
|
if (post.reactionEnabled && !widget.isOverviewScreen!)
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: ReactionBottom(
|
child: ReactionBottom(
|
||||||
|
|
|
@ -273,8 +273,9 @@ class _TimelineScreenState extends State<TimelineScreen> {
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
category == null
|
category == null
|
||||||
? widget.options.translations.noPosts
|
? widget.options.translations.noPosts!
|
||||||
: widget.options.translations.noPostsWithFilter,
|
: widget
|
||||||
|
.options.translations.noPostsWithFilter!,
|
||||||
style: widget.options.theme.textStyles.noPostsStyle,
|
style: widget.options.theme.textStyles.noPostsStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -19,7 +19,6 @@ class TimelineSelectionScreen extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var size = MediaQuery.of(context).size;
|
var size = MediaQuery.of(context).size;
|
||||||
var theme = Theme.of(context);
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: size.width * 0.05,
|
horizontal: size.width * 0.05,
|
||||||
|
@ -30,33 +29,52 @@ class TimelineSelectionScreen extends StatelessWidget {
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: size.height * 0.05, bottom: 8),
|
padding: EdgeInsets.only(top: size.height * 0.05, bottom: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
options.translations.timelineSelectionDescription,
|
options.translations.timelineSelectionDescription!,
|
||||||
style:
|
style: const TextStyle(
|
||||||
options.theme.textStyles.categorySelectionDescriptionStyle ??
|
fontWeight: FontWeight.w800,
|
||||||
theme.textTheme.displayMedium,
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
for (var category in categories.where(
|
for (var category in categories.where(
|
||||||
(element) => element.canCreate,
|
(element) => element.canCreate,
|
||||||
)) ...[
|
)) ...[
|
||||||
|
options.categorySelectorButtonBuilder?.call(
|
||||||
|
context,
|
||||||
|
() {
|
||||||
|
onCategorySelected.call(category);
|
||||||
|
},
|
||||||
|
category.title,
|
||||||
|
) ??
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () => onCategorySelected.call(category),
|
onTap: () => onCategorySelected.call(category),
|
||||||
child: Container(
|
child: Container(
|
||||||
|
height: 60,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
color: const Color(0xff71C6D1),
|
||||||
|
width: 2,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 26,
|
|
||||||
horizontal: 16,
|
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
category.title,
|
category.title,
|
||||||
style: options.theme.textStyles.categorySelectionTitleStyle ??
|
style: const TextStyle(
|
||||||
theme.textTheme.displaySmall,
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -21,8 +21,8 @@ class LocalTimelinePostService
|
||||||
userId: 'test_user',
|
userId: 'test_user',
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
||||||
firstName: 'Dirk',
|
firstName: 'Ico',
|
||||||
lastName: 'lukassen',
|
lastName: 'Nica',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -174,8 +174,8 @@ class LocalTimelinePostService
|
||||||
userId: 'test_user',
|
userId: 'test_user',
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
||||||
firstName: 'Dirk',
|
firstName: 'Ico',
|
||||||
lastName: 'lukassen',
|
lastName: 'Nica',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -197,63 +197,47 @@ class LocalTimelinePostService
|
||||||
TimelinePost(
|
TimelinePost(
|
||||||
id: 'Post0',
|
id: 'Post0',
|
||||||
creatorId: 'test_user',
|
creatorId: 'test_user',
|
||||||
title: 'Post 0',
|
title: 'De topper van de maand september',
|
||||||
category: null,
|
category: 'Category',
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://t4.ftcdn.net/jpg/02/77/71/45/240_F_277714513_fQ0akmI3TQxa0wkPCLeO12Rx3cL2AuIf.jpg',
|
'https://firebasestorage.googleapis.com/v0/b/appshell-demo.appspot.com/o/do_not_delete_1.png?alt=media&token=e4b2f9f3-c81f-4ac7-a938-e846691399f7',
|
||||||
content: 'Standard post without image made by the current user',
|
content: 'Dit is onze topper van de maand september! Gefeliciteerd!',
|
||||||
likes: 0,
|
likes: 72,
|
||||||
reaction: 0,
|
reaction: 0,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
reactionEnabled: false,
|
reactionEnabled: true,
|
||||||
creator: const TimelinePosterUserModel(
|
creator: const TimelinePosterUserModel(
|
||||||
userId: 'test_user',
|
userId: 'test_user',
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
'https://firebasestorage.googleapis.com/v0/b/appshell-demo.appspot.com/o/do_not_delete_3.png?alt=media&token=cd7c156d-0dda-43be-9199-f7d31c30132e',
|
||||||
firstName: 'Dirk',
|
firstName: 'Robin',
|
||||||
lastName: 'lukassen',
|
lastName: 'De Vries',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TimelinePost(
|
TimelinePost(
|
||||||
id: 'Post1',
|
id: 'Post1',
|
||||||
creatorId: 'test_user2',
|
creatorId: 'test_user2',
|
||||||
title: 'Post 1',
|
title: 'De soep van de week is: Aspergesoep',
|
||||||
category: null,
|
category: 'Category with two lines',
|
||||||
content: 'Standard post with image made by a different user and '
|
content:
|
||||||
'reactions enabled',
|
'Aspergesoep is echt een heerlijke delicatesse. Deze soep wordt'
|
||||||
likes: 0,
|
' vaak gemaakt met verse asperges, bouillon en wat kruiden voor'
|
||||||
reaction: 0,
|
' smaak. Het is een perfecte keuze voor een lichte en smaakvolle'
|
||||||
createdAt: DateTime.now(),
|
' maaltijd, vooral in het voorjaar wanneer asperges in seizoen'
|
||||||
reactionEnabled: false,
|
' zijn. We serveren het met een vleugje room en wat knapperige'
|
||||||
imageUrl:
|
' croutons voor die extra touch.',
|
||||||
'https://t4.ftcdn.net/jpg/02/77/71/45/240_F_277714513_fQ0akmI3TQxa0wkPCLeO12Rx3cL2AuIf.jpg',
|
likes: 72,
|
||||||
creator: const TimelinePosterUserModel(
|
|
||||||
userId: 'test_user',
|
|
||||||
imageUrl:
|
|
||||||
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
|
||||||
firstName: 'Dirk',
|
|
||||||
lastName: 'lukassen',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TimelinePost(
|
|
||||||
id: 'Post2',
|
|
||||||
creatorId: 'test_user',
|
|
||||||
title: 'Post 2',
|
|
||||||
category: null,
|
|
||||||
content: 'Standard post with image made by the current user and'
|
|
||||||
' reactions enabled',
|
|
||||||
likes: 0,
|
|
||||||
reaction: 0,
|
reaction: 0,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
reactionEnabled: true,
|
reactionEnabled: true,
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://t4.ftcdn.net/jpg/02/77/71/45/240_F_277714513_fQ0akmI3TQxa0wkPCLeO12Rx3cL2AuIf.jpg',
|
'https://firebasestorage.googleapis.com/v0/b/appshell-demo.appspot.com/o/do_not_delete_2.png?alt=media&token=ee4a8771-531f-4d1d-8613-a2366771e775',
|
||||||
creator: const TimelinePosterUserModel(
|
creator: const TimelinePosterUserModel(
|
||||||
userId: 'test_user',
|
userId: 'test_user',
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'https://cdn.britannica.com/68/143568-050-5246474F/Donkey.jpg?w=400&h=300&c=crop',
|
'https://firebasestorage.googleapis.com/v0/b/appshell-demo.appspot.com/o/do_not_delete_4.png?alt=media&token=775d4d10-6d2b-4aef-a51b-ba746b7b137f',
|
||||||
firstName: 'Dirk',
|
firstName: 'Elise',
|
||||||
lastName: 'lukassen',
|
lastName: 'Welling',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
|
@ -41,10 +41,11 @@ class _CategorySelectorState extends State<CategorySelector> {
|
||||||
),
|
),
|
||||||
for (var category in categories) ...[
|
for (var category in categories) ...[
|
||||||
widget.options.categoriesOptions.categoryButtonBuilder?.call(
|
widget.options.categoriesOptions.categoryButtonBuilder?.call(
|
||||||
categoryKey: category.key,
|
category.key,
|
||||||
categoryName: category.title,
|
category.title,
|
||||||
onTap: () => widget.onTapCategory(category.key),
|
() => widget.onTapCategory(category.key),
|
||||||
selected: widget.filter == category.key,
|
widget.filter == category.key,
|
||||||
|
widget.isOnTop,
|
||||||
) ??
|
) ??
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
|
|
@ -22,9 +22,8 @@ class CategorySelectorButton extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
|
|
||||||
return AnimatedContainer(
|
return SizedBox(
|
||||||
height: isOnTop ? 140 : 40,
|
height: isOnTop ? 140 : 40,
|
||||||
duration: const Duration(milliseconds: 100),
|
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: onTap,
|
onPressed: onTap,
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
|
@ -37,26 +36,26 @@ class CategorySelectorButton extends StatelessWidget {
|
||||||
),
|
),
|
||||||
fixedSize: MaterialStatePropertyAll(Size(140, isOnTop ? 140 : 20)),
|
fixedSize: MaterialStatePropertyAll(Size(140, isOnTop ? 140 : 20)),
|
||||||
backgroundColor: MaterialStatePropertyAll(
|
backgroundColor: MaterialStatePropertyAll(
|
||||||
selected ? theme.colorScheme.primary : Colors.transparent,
|
selected ? const Color(0xff71C6D1) : Colors.transparent,
|
||||||
),
|
),
|
||||||
shape: MaterialStatePropertyAll(
|
shape: const MaterialStatePropertyAll(
|
||||||
RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(8),
|
Radius.circular(8),
|
||||||
),
|
),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: theme.colorScheme.primary,
|
color: Color(0xff71C6D1),
|
||||||
width: 2,
|
width: 2,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: isOnTop
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
? SizedBox(
|
||||||
children: [
|
width: MediaQuery.of(context).size.width,
|
||||||
Column(
|
child: Column(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
isOnTop ? MainAxisAlignment.end : MainAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
category.title,
|
category.title,
|
||||||
|
@ -67,9 +66,27 @@ class CategorySelectorButton extends StatelessWidget {
|
||||||
? theme.colorScheme.onPrimary
|
? theme.colorScheme.onPrimary
|
||||||
: theme.colorScheme.onSurface,
|
: theme.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
: Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
category.title,
|
||||||
|
style: (options.theme.textStyles.categoryTitleStyle ??
|
||||||
|
theme.textTheme.labelLarge)
|
||||||
|
?.copyWith(
|
||||||
|
color: selected
|
||||||
|
? theme.colorScheme.onPrimary
|
||||||
|
: theme.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -65,7 +65,7 @@ class _ReactionBottomState extends State<ReactionBottom> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
widget.translations.writeComment,
|
widget.translations.writeComment!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -99,10 +99,16 @@ class _TappableImageState extends State<TappableImage>
|
||||||
offset: Offset(0, animation.value * -32),
|
offset: Offset(0, animation.value * -32),
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 1 + animation.value * 0.1,
|
scale: 1 + animation.value * 0.1,
|
||||||
child: CachedNetworkImage(
|
child: widget.post.imageUrl != null
|
||||||
|
? CachedNetworkImage(
|
||||||
imageUrl: widget.post.imageUrl ?? '',
|
imageUrl: widget.post.imageUrl ?? '',
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
fit: BoxFit.fitHeight,
|
fit: BoxFit.fitHeight,
|
||||||
|
)
|
||||||
|
: Image.memory(
|
||||||
|
width: double.infinity,
|
||||||
|
widget.post.image!,
|
||||||
|
fit: BoxFit.fitHeight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -49,7 +49,7 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: widget.onTap,
|
onTap: widget.onTap,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: widget.post.imageUrl != null
|
height: widget.post.imageUrl != null || widget.post.image != null
|
||||||
? widget.options.postWidgetHeight
|
? widget.options.postWidgetHeight
|
||||||
: null,
|
: null,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
@ -94,7 +94,7 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
widget.options.nameBuilder
|
widget.options.nameBuilder
|
||||||
?.call(widget.post.creator) ??
|
?.call(widget.post.creator) ??
|
||||||
widget.post.creator?.fullName ??
|
widget.post.creator?.fullName ??
|
||||||
widget.options.translations.anonymousUser,
|
widget.options.translations.anonymousUser!,
|
||||||
style: widget.options.theme.textStyles
|
style: widget.options.theme.textStyles
|
||||||
.postCreatorTitleStyle ??
|
.postCreatorTitleStyle ??
|
||||||
theme.textTheme.titleMedium,
|
theme.textTheme.titleMedium,
|
||||||
|
@ -118,7 +118,7 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.deletePost,
|
widget.options.translations.deletePost!,
|
||||||
style: widget.options.theme.textStyles
|
style: widget.options.theme.textStyles
|
||||||
.deletePostStyle ??
|
.deletePostStyle ??
|
||||||
theme.textTheme.bodyMedium,
|
theme.textTheme.bodyMedium,
|
||||||
|
@ -142,7 +142,7 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// image of the post
|
// image of the post
|
||||||
if (widget.post.imageUrl != null) ...[
|
if (widget.post.imageUrl != null || widget.post.image != null) ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Flexible(
|
Flexible(
|
||||||
flex: widget.options.postWidgetHeight != null ? 1 : 0,
|
flex: widget.options.postWidgetHeight != null ? 1 : 0,
|
||||||
|
@ -176,10 +176,16 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
return result.likedBy?.contains(userId) ?? false;
|
return result.likedBy?.contains(userId) ?? false;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: CachedNetworkImage(
|
: widget.post.imageUrl != null
|
||||||
|
? CachedNetworkImage(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
imageUrl: widget.post.imageUrl!,
|
imageUrl: widget.post.imageUrl!,
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
|
)
|
||||||
|
: Image.memory(
|
||||||
|
width: double.infinity,
|
||||||
|
widget.post.image!,
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -312,7 +318,7 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
widget.options.translations.viewPost,
|
widget.options.translations.viewPost!,
|
||||||
style: widget.options.theme.textStyles.viewPostStyle ??
|
style: widget.options.theme.textStyles.viewPostStyle ??
|
||||||
theme.textTheme.bodySmall,
|
theme.textTheme.bodySmall,
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
name: flutter_timeline_view
|
name: flutter_timeline_view
|
||||||
description: Visual elements of the Flutter Timeline Component
|
description: Visual elements of the Flutter Timeline Component
|
||||||
version: 2.3.1
|
version: 3.0.0
|
||||||
|
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_timeline
|
url: https://github.com/Iconica-Development/flutter_timeline
|
||||||
path: packages/flutter_timeline_interface
|
path: packages/flutter_timeline_interface
|
||||||
ref: 2.3.1
|
ref: 3.0.0
|
||||||
flutter_image_picker:
|
flutter_image_picker:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_image_picker
|
url: https://github.com/Iconica-Development/flutter_image_picker
|
||||||
|
|
Loading…
Reference in a new issue