Skip to content

Android keyboard image support #1643

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,14 @@
"@topicValidationErrorMandatoryButEmpty": {
"description": "Topic validation error when topic is required but was empty."
},
"errorContentNotInsertedTitle": "Content not inserted",
"@errorContentNotInsertedTitle": {
"description": "Title for error dialog when an attempt to insert rich content failed."
},
"errorContentToInsertIsEmpty": "The file to be inserted is empty or cannot be accessed.",
"@errorContentToInsertIsEmpty": {
"description": "Error message when the rich content to be inserted is empty or cannot be accessed."
},
"errorServerVersionUnsupportedMessage": "{url} is running Zulip Server {zulipVersion}, which is unsupported. The minimum supported version is Zulip Server {minSupportedZulipVersion}.",
"@errorServerVersionUnsupportedMessage": {
"description": "Error message in the dialog for when the Zulip Server version is unsupported.",
Expand Down
12 changes: 12 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,18 @@ abstract class ZulipLocalizations {
/// **'Topics are required in this organization.'**
String get topicValidationErrorMandatoryButEmpty;

/// Title for error dialog when an attempt to insert rich content failed.
///
/// In en, this message translates to:
/// **'Content not inserted'**
String get errorContentNotInsertedTitle;

/// Error message when the rich content to be inserted is empty or cannot be accessed.
///
/// In en, this message translates to:
/// **'The file to be inserted is empty or cannot be accessed.'**
String get errorContentToInsertIsEmpty;

/// Error message in the dialog for when the Zulip Server version is unsupported.
///
/// In en, this message translates to:
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,13 @@ class ZulipLocalizationsDe extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Themen sind in dieser Organisation erforderlich.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ class ZulipLocalizationsIt extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'In questa organizzazione sono richiesti degli argomenti.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Wątki są wymagane przez tę organizację.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Темы обязательны в этой организации.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_sl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,13 @@ class ZulipLocalizationsSl extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Teme so v tej organizaciji obvezne.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_uk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,13 @@ class ZulipLocalizationsUk extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Теми обовʼязкові в цій організації.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
7 changes: 7 additions & 0 deletions lib/generated/l10n/zulip_localizations_zh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class ZulipLocalizationsZh extends ZulipLocalizations {
String get topicValidationErrorMandatoryButEmpty =>
'Topics are required in this organization.';

@override
String get errorContentNotInsertedTitle => 'Content not inserted';

@override
String get errorContentToInsertIsEmpty =>
'The file to be inserted is empty or cannot be accessed.';

@override
String errorServerVersionUnsupportedMessage(
String url,
Expand Down
37 changes: 37 additions & 0 deletions lib/widgets/compose_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:mime/mime.dart';
import 'package:path/path.dart' as path;

import '../api/exception.dart';
import '../api/model/model.dart';
Expand Down Expand Up @@ -508,6 +509,40 @@ class _ContentInput extends StatelessWidget {
final String? hintText;
final bool enabled;

void _handleContentInserted(KeyboardInsertedContent content,
BuildContext context) async {
if (content.data == null || content.data!.isEmpty) {
// As of writing, the engine implementation never leaves `content.data` as
// `null`, but ideally it should be when the data cannot be read for
// errors.
//
// When `content.data` is empty, the data is not literally empty — this
// can also happen when the data can't be read from the input stream
// provided by the Android SDK because of an IO exception.
//
// See Flutter engine implementation that prepares this data:
// https://github.com/flutter/flutter/blob/0ffc4ce00/engine/src/flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java#L497-L548
// TODO(upstream): improve the API for this
final zulipLocalizations = ZulipLocalizations.of(context);
showErrorDialog(context: context,
title: zulipLocalizations.errorContentNotInsertedTitle,
message: zulipLocalizations.errorContentToInsertIsEmpty);
return;
}

final file = _File(
content: Stream.fromIterable([content.data!]),
length: content.data!.length,
filename: path.basename(content.uri),
mimeType: content.mimeType);

await _uploadFiles(
context: context,
contentController: controller.content,
contentFocusNode: controller.contentFocusNode,
files: [file]);
}

static double maxHeight(BuildContext context) {
final clampingTextScaler = MediaQuery.textScalerOf(context)
.clamp(maxScaleFactor: 1.5);
Expand Down Expand Up @@ -552,6 +587,8 @@ class _ContentInput extends StatelessWidget {
enabled: enabled,
controller: controller.content,
focusNode: controller.contentFocusNode,
contentInsertionConfiguration: ContentInsertionConfiguration(
onContentInserted: (content) => _handleContentInserted(content, context)),
// Let the content show through the `contentPadding` so that
// our [InsetShadowBox] can fade it smoothly there.
clipBehavior: Clip.none,
Expand Down
Loading