Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing calendar action in news creation #2096

Merged
merged 5 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .changes/2996-proper-calendar-event-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [Fix] we were not correctly referencing News Calendar Events, we now have support to render external links, too.
175 changes: 175 additions & 0 deletions app/lib/features/news/actions/submit_news.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import 'package:acter/common/providers/sdk_provider.dart';
gnunicorn marked this conversation as resolved.
Show resolved Hide resolved
import 'package:acter/common/providers/space_providers.dart';
import 'package:acter/common/utils/routes.dart';
import 'package:acter/features/home/providers/client_providers.dart';
import 'package:acter/features/news/model/news_references_model.dart';
import 'package:acter/features/news/model/news_slide_model.dart';
import 'package:acter/features/news/providers/news_post_editor_providers.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:mime/mime.dart';

final _log = Logger('a3::news::send_news');

Future<void> sendNews(BuildContext context, WidgetRef ref) async {
// Hide Keyboard
SystemChannels.textInput.invokeMethod('TextInput.hide');
final client = ref.read(alwaysClientProvider);
final spaceId = ref.read(newsStateProvider).newsPostSpaceId;
final newsSlideList = ref.read(newsStateProvider).newsSlideList;
final lang = L10n.of(context);

if (spaceId == null) {
EasyLoading.showToast(L10n.of(context).pleaseFirstSelectASpace);
return;
}

// Show loading message
EasyLoading.show(status: L10n.of(context).slidePosting);
try {
final space = await ref.read(spaceProvider(spaceId).future);
NewsEntryDraft draft = space.newsDraft();
for (final slidePost in newsSlideList) {
final sdk = await ref.read(sdkProvider.future);
// If slide type is text
if (slidePost.type == NewsSlideType.text) {
if (slidePost.text == null || slidePost.text!.trim().isEmpty) {
if (!context.mounted) {
EasyLoading.dismiss();
return;
}
EasyLoading.showError(
L10n.of(context).yourTextSlidesMustContainsSomeText,
duration: const Duration(seconds: 3),
);
return;
}
final textDraft = slidePost.html != null
? client.textHtmlDraft(slidePost.html!, slidePost.text!)
: client.textMarkdownDraft(slidePost.text!);
final textSlideDraft = textDraft.intoNewsSlideDraft();

textSlideDraft.color(
sdk.api.newColorizeBuilder(null, slidePost.backgroundColor?.value),
);

if (slidePost.newsReferencesModel != null) {
final objRef = getSlideReference(sdk, slidePost.newsReferencesModel!);
textSlideDraft.addReference(objRef);
}
await draft.addSlide(textSlideDraft);
}

// If slide type is image
else if (slidePost.type == NewsSlideType.image &&
slidePost.mediaFile != null) {
final file = slidePost.mediaFile!;
String? mimeType = file.mimeType ?? lookupMimeType(file.path);
if (mimeType == null) throw lang.failedToDetectMimeType;
if (!mimeType.startsWith('image/')) {
if (!context.mounted) {
EasyLoading.dismiss();
return;
}
EasyLoading.showError(
L10n.of(context).postingOfTypeNotYetSupported(mimeType),
duration: const Duration(seconds: 3),
);
return;
}
Uint8List bytes = await file.readAsBytes();
final decodedImage = await decodeImageFromList(bytes);
final imageDraft = client
.imageDraft(file.path, mimeType)
.size(bytes.length)
.width(decodedImage.width)
.height(decodedImage.height);
final imageSlideDraft = imageDraft.intoNewsSlideDraft();
imageSlideDraft.color(
sdk.api.newColorizeBuilder(null, slidePost.backgroundColor?.value),
);
if (slidePost.newsReferencesModel != null) {
final objRef = getSlideReference(sdk, slidePost.newsReferencesModel!);
imageSlideDraft.addReference(objRef);
}
await draft.addSlide(imageSlideDraft);
}

// If slide type is video
else if (slidePost.type == NewsSlideType.video &&
slidePost.mediaFile != null) {
final file = slidePost.mediaFile!;
String? mimeType = file.mimeType ?? lookupMimeType(file.path);
if (mimeType == null) throw lang.failedToDetectMimeType;
if (!mimeType.startsWith('video/')) {
if (!context.mounted) {
EasyLoading.dismiss();
return;
}
EasyLoading.showError(
L10n.of(context).postingOfTypeNotYetSupported(mimeType),
duration: const Duration(seconds: 3),
);
return;
}
Uint8List bytes = await file.readAsBytes();
final videoDraft =
client.videoDraft(file.path, mimeType).size(bytes.length);
final videoSlideDraft = videoDraft.intoNewsSlideDraft();
videoSlideDraft.color(
sdk.api.newColorizeBuilder(null, slidePost.backgroundColor?.value),
);
if (slidePost.newsReferencesModel != null) {
final objRef = getSlideReference(sdk, slidePost.newsReferencesModel!);
videoSlideDraft.addReference(objRef);
}
await draft.addSlide(videoSlideDraft);
}
}
await draft.send();

// close loading
EasyLoading.dismiss();

if (!context.mounted) return;
// FIXME due to #718. well lets at least try forcing a refresh upon route.
ref.invalidate(newsStateProvider);
// Navigate back to update screen.
Navigator.pop(context);
context.pushReplacementNamed(
Routes.main.name,
); // go to the home / main updates
} catch (e, s) {
_log.severe('Failed to send news', e, s);
if (!context.mounted) {
EasyLoading.dismiss();
return;
}
EasyLoading.showError(
L10n.of(context).creatingNewsFailed(e),
duration: const Duration(seconds: 3),
);
}
}

ObjRef getSlideReference(
ActerSdk sdk,
NewsReferencesModel newsReferencesModel,
) {
final refDetails = switch (newsReferencesModel.type) {
NewsReferencesType.calendarEvent => sdk.api
.newCalendarEventRefBuilder(newsReferencesModel.id!, null, null)
.build(),
NewsReferencesType.link => sdk.api
.newLinkRefBuilder(newsReferencesModel.title!, newsReferencesModel.id!)
.build(),
};
return sdk.api.newObjRefBuilder(null, refDetails).build();
}
19 changes: 18 additions & 1 deletion app/lib/features/news/model/news_references_model.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
enum NewsReferencesType {
shareEvent,
calendarEvent,
link;

static NewsReferencesType? fromStr(String typeStr) {
return values.asNameMap()[_toCamelCase(typeStr)];
}
}

String _toCamelCase(String s) {
final words = s
.split('-')
.map((w) =>
'${w.substring(0, 1).toUpperCase()}${w.substring(1).toLowerCase()}',)
.toList();
words[0] = words[0].toLowerCase();
return words.join();
Comment on lines +5 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite understand this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it rewrites strings from things-named-like-this to thingsNamedLikeThis

}

class NewsReferencesModel {
NewsReferencesType type;
String? id;
String? title;

NewsReferencesModel({
required this.type,
this.title,
this.id,
});
}
Loading
Loading