Merge pull request #518 from GetStream/feat/localization
feat(ui, repo): stream_chat_localizations [CDS-318]
@@ -21,6 +21,7 @@ jobs:
|
|||||||
ui
|
ui
|
||||||
doc
|
doc
|
||||||
repo
|
repo
|
||||||
|
localization
|
||||||
requireScope: true
|
requireScope: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ This package provides business logic to fetch common things required for integra
|
|||||||
### [stream_chat_flutter](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_flutter)
|
### [stream_chat_flutter](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_flutter)
|
||||||
This library includes both a low-level chat SDK and a set of reusable and customizable UI components.
|
This library includes both a low-level chat SDK and a set of reusable and customizable UI components.
|
||||||
|
|
||||||
|
### [stream_chat_localizations](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_localizations)
|
||||||
|
This library includes a set of localization files for the Flutter UI components.
|
||||||
|
|
||||||
## Flutter Chat Tutorial
|
## Flutter Chat Tutorial
|
||||||
|
|
||||||
The best place to start is the [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/).
|
The best place to start is the [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/).
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ scripts:
|
|||||||
|
|
||||||
analyze:
|
analyze:
|
||||||
run: |
|
run: |
|
||||||
melos exec -c 4 --ignore="*example*" -- \
|
melos exec -c 5 --ignore="*example*" -- \
|
||||||
dart analyze --fatal-infos .
|
dart analyze --fatal-infos .
|
||||||
description: |
|
description: |
|
||||||
Run `dart analyze` in all packages.
|
Run `dart analyze` in all packages.
|
||||||
@@ -26,7 +26,7 @@ scripts:
|
|||||||
|
|
||||||
lint:pub:
|
lint:pub:
|
||||||
run: |
|
run: |
|
||||||
melos exec -c 4 --no-private --ignore="*example*" -- \
|
melos exec -c 5 --no-private --ignore="*example*" -- \
|
||||||
pub publish --dry-run
|
pub publish --dry-run
|
||||||
description: |
|
description: |
|
||||||
Run `pub publish --dry-run` in all packages.
|
Run `pub publish --dry-run` in all packages.
|
||||||
@@ -56,7 +56,7 @@ scripts:
|
|||||||
dir-exists: test
|
dir-exists: test
|
||||||
|
|
||||||
test:flutter:
|
test:flutter:
|
||||||
run: melos exec -c 3 --fail-fast -- "flutter test --coverage"
|
run: melos exec -c 4 --fail-fast -- "flutter test --coverage"
|
||||||
description: Run Flutter tests for a specific package in this project.
|
description: Run Flutter tests for a specific package in this project.
|
||||||
select-package:
|
select-package:
|
||||||
flutter: true
|
flutter: true
|
||||||
@@ -64,7 +64,7 @@ scripts:
|
|||||||
|
|
||||||
coverage:ignore-file:
|
coverage:ignore-file:
|
||||||
run: |
|
run: |
|
||||||
melos exec -c 4 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/remove-from-coverage.sh"
|
melos exec -c 5 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/remove-from-coverage.sh"
|
||||||
description: Removes all the ignored files from the coverage report.
|
description: Removes all the ignored files from the coverage report.
|
||||||
select-package:
|
select-package:
|
||||||
dir-exists: coverage
|
dir-exists: coverage
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
|
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||||
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
|
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
|
||||||
|
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
Check out the [changelog on pub.dev](https://pub.dev/packages/stream_chat_flutter/changelog) to see the latest changes in the package.
|
Check out the [changelog on pub.dev](https://pub.dev/packages/stream_chat_flutter/changelog) to see the latest changes in the package.
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_persistence/stream_chat_persistence.dart';
|
import 'package:stream_chat_localizations/stream_chat_localizations.dart';
|
||||||
|
|
||||||
/// A chat-persisted StreamChatClient
|
|
||||||
final chatPersistentClient = StreamChatPersistenceClient(
|
|
||||||
logLevel: Level.INFO,
|
|
||||||
);
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@@ -15,7 +12,7 @@ void main() async {
|
|||||||
final client = StreamChatClient(
|
final client = StreamChatClient(
|
||||||
's2dxdhpxd94g',
|
's2dxdhpxd94g',
|
||||||
logLevel: Level.INFO,
|
logLevel: Level.INFO,
|
||||||
)..chatPersistenceClient = chatPersistentClient;
|
);
|
||||||
|
|
||||||
/// Set the current user and connect the websocket. In a production
|
/// Set the current user and connect the websocket. In a production
|
||||||
/// scenario, this should be done using a backend to generate a user token
|
/// scenario, this should be done using a backend to generate a user token
|
||||||
@@ -72,6 +69,13 @@ class MyApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) => MaterialApp(
|
Widget build(BuildContext context) => MaterialApp(
|
||||||
theme: ThemeData.light(),
|
theme: ThemeData.light(),
|
||||||
darkTheme: ThemeData.dark(),
|
darkTheme: ThemeData.dark(),
|
||||||
|
supportedLocales: const [
|
||||||
|
Locale('en'),
|
||||||
|
Locale('hi'),
|
||||||
|
Locale('fr'),
|
||||||
|
Locale('it'),
|
||||||
|
],
|
||||||
|
localizationsDelegates: GlobalStreamChatLocalizations.delegates,
|
||||||
builder: (context, widget) => StreamChat(
|
builder: (context, widget) => StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
child: widget,
|
child: widget,
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ dependencies:
|
|||||||
# path: ../../stream_chat_flutter_core
|
# path: ../../stream_chat_flutter_core
|
||||||
stream_chat_flutter:
|
stream_chat_flutter:
|
||||||
path: ../
|
path: ../
|
||||||
|
stream_chat_localizations:
|
||||||
|
path: ../../stream_chat_localizations
|
||||||
stream_chat_persistence:
|
stream_chat_persistence:
|
||||||
path: ../../stream_chat_persistence
|
path: ../../stream_chat_persistence
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
|
import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget to build in progress
|
/// Widget to build in progress
|
||||||
typedef InProgressBuilder = Widget Function(BuildContext, int, int);
|
typedef InProgressBuilder = Widget Function(BuildContext, int, int);
|
||||||
@@ -226,7 +227,7 @@ class _FailedState extends StatelessWidget {
|
|||||||
horizontal: 12,
|
horizontal: 12,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'UPLOAD ERROR',
|
context.translations.uploadErrorLabel,
|
||||||
style: theme.textTheme.footnote.copyWith(
|
style: theme.textTheme.footnote.copyWith(
|
||||||
color: theme.colorTheme.barsBg,
|
color: theme.colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
|
|||||||
import 'package:stream_chat_flutter/src/utils.dart';
|
import 'package:stream_chat_flutter/src/utils.dart';
|
||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
// ignore: always_use_package_imports
|
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
||||||
import 'attachment_widget.dart';
|
|
||||||
|
|
||||||
/// Widget for displaying file attachments
|
/// Widget for displaying file attachments
|
||||||
class FileAttachment extends AttachmentWidget {
|
class FileAttachment extends AttachmentWidget {
|
||||||
@@ -76,7 +76,7 @@ class FileAttachment extends AttachmentWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
attachment.title ?? 'File',
|
attachment.title ?? context.translations.fileText,
|
||||||
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -286,7 +286,10 @@ class FileAttachment extends AttachmentWidget {
|
|||||||
progressIndicatorColor: theme.colorTheme.accentPrimary,
|
progressIndicatorColor: theme.colorTheme.accentPrimary,
|
||||||
),
|
),
|
||||||
success: () => Text(fileSize(size), style: textStyle),
|
success: () => Text(fileSize(size), style: textStyle),
|
||||||
failed: (_) => Text('UPLOAD ERROR', style: textStyle),
|
failed: (_) => Text(
|
||||||
|
context.translations.uploadErrorLabel,
|
||||||
|
style: textStyle,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
|||||||
import 'package:stream_chat_flutter/src/visible_footnote.dart';
|
import 'package:stream_chat_flutter/src/visible_footnote.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget for showing a GIF attachment
|
/// Widget for showing a GIF attachment
|
||||||
class GiphyAttachment extends AttachmentWidget {
|
class GiphyAttachment extends AttachmentWidget {
|
||||||
@@ -72,9 +73,9 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.giphyIcon(),
|
StreamSvgIcon.giphyIcon(),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const Text(
|
Text(
|
||||||
'Giphy',
|
context.translations.giphyLabel,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
if (attachment.title != null)
|
if (attachment.title != null)
|
||||||
@@ -135,7 +136,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Cancel',
|
context.translations.cancelLabel.toLowerCase(),
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyBold
|
.bodyBold
|
||||||
@@ -167,7 +168,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Shuffle',
|
context.translations.shuffleLabel,
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyBold
|
.bodyBold
|
||||||
@@ -200,7 +201,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Send',
|
context.translations.sendLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.colorTheme
|
.colorTheme
|
||||||
@@ -315,7 +316,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'GIPHY',
|
context.translations.giphyLabel.toUpperCase(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color:
|
color:
|
||||||
StreamChatTheme.of(context).colorTheme.barsBg,
|
StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
child: _buildPage(context),
|
child: _buildPage(context),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPage(context) {
|
Widget _buildPage(BuildContext context) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
@@ -69,7 +69,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildButton(
|
_buildButton(
|
||||||
context,
|
context,
|
||||||
'Reply',
|
context.translations.replyLabel,
|
||||||
StreamSvgIcon.iconCurveLineLeftUp(
|
StreamSvgIcon.iconCurveLineLeftUp(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: theme.colorTheme.textLowEmphasis,
|
color: theme.colorTheme.textLowEmphasis,
|
||||||
@@ -80,7 +80,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
_buildButton(
|
_buildButton(
|
||||||
context,
|
context,
|
||||||
'Show in Chat',
|
context.translations.showInChatLabel,
|
||||||
StreamSvgIcon.eye(
|
StreamSvgIcon.eye(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: theme.colorTheme.textHighEmphasis,
|
color: theme.colorTheme.textHighEmphasis,
|
||||||
@@ -89,8 +89,9 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
_buildButton(
|
_buildButton(
|
||||||
context,
|
context,
|
||||||
// ignore: lines_longer_than_80_chars
|
message.attachments[currentIndex].type == 'video'
|
||||||
'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
? context.translations.saveVideoLabel
|
||||||
|
: context.translations.saveImageLabel,
|
||||||
StreamSvgIcon.iconSave(
|
StreamSvgIcon.iconSave(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: theme.colorTheme.textLowEmphasis,
|
color: theme.colorTheme.textLowEmphasis,
|
||||||
@@ -142,7 +143,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
message.user?.id)
|
message.user?.id)
|
||||||
_buildButton(
|
_buildButton(
|
||||||
context,
|
context,
|
||||||
'Delete',
|
context.translations.deleteLabel.capitalize(),
|
||||||
StreamSvgIcon.delete(
|
StreamSvgIcon.delete(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: theme.colorTheme.accentError,
|
color: theme.colorTheme.accentError,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/channel_info.dart';
|
import 'package:stream_chat_flutter/src/channel_info.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Bottom Sheet with options
|
/// Bottom Sheet with options
|
||||||
class ChannelBottomSheet extends StatefulWidget {
|
class ChannelBottomSheet extends StatefulWidget {
|
||||||
@@ -149,7 +150,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: 'View Info',
|
title: context.translations.viewInfoLabel,
|
||||||
onTap: widget.onViewInfoTap,
|
onTap: widget.onViewInfoTap,
|
||||||
),
|
),
|
||||||
if (!channel.isDistinct)
|
if (!channel.isDistinct)
|
||||||
@@ -160,7 +161,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: 'Leave Group',
|
title: context.translations.leaveGroupLabel,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
_showActions = false;
|
_showActions = false;
|
||||||
@@ -179,7 +180,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
color: _streamChatThemeData.colorTheme.accentError,
|
color: _streamChatThemeData.colorTheme.accentError,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: 'Delete Conversation',
|
title: context.translations.deleteConversationLabel,
|
||||||
titleColor: _streamChatThemeData.colorTheme.accentError,
|
titleColor: _streamChatThemeData.colorTheme.accentError,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -198,7 +199,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
color: _streamChatThemeData.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: 'Cancel',
|
title: context.translations.cancelLabel,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
@@ -219,10 +220,10 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
Future<void> _showDeleteDialog() async {
|
Future<void> _showDeleteDialog() async {
|
||||||
final res = await showConfirmationDialog(
|
final res = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
title: 'Delete Conversation',
|
title: context.translations.deleteConversationLabel,
|
||||||
okText: 'DELETE',
|
okText: context.translations.deleteLabel,
|
||||||
question: 'Are you sure you want to delete this conversation?',
|
question: context.translations.deleteConversationQuestion,
|
||||||
cancelText: 'CANCEL',
|
cancelText: context.translations.cancelLabel,
|
||||||
icon: StreamSvgIcon.delete(
|
icon: StreamSvgIcon.delete(
|
||||||
color: _streamChatThemeData.colorTheme.accentError,
|
color: _streamChatThemeData.colorTheme.accentError,
|
||||||
),
|
),
|
||||||
@@ -237,10 +238,10 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
Future<void> _showLeaveDialog() async {
|
Future<void> _showLeaveDialog() async {
|
||||||
final res = await showConfirmationDialog(
|
final res = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
title: 'Leave conversation',
|
title: context.translations.leaveConversationLabel,
|
||||||
okText: 'LEAVE',
|
okText: context.translations.leaveLabel,
|
||||||
question: 'Are you sure you want to leave this conversation?',
|
question: context.translations.leaveConversationQuestion,
|
||||||
cancelText: 'CANCEL',
|
cancelText: context.translations.cancelLabel,
|
||||||
icon: StreamSvgIcon.userRemove(
|
icon: StreamSvgIcon.userRemove(
|
||||||
color: _streamChatThemeData.colorTheme.accentError,
|
color: _streamChatThemeData.colorTheme.accentError,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:stream_chat_flutter/src/info_tile.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
@@ -121,14 +122,14 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus.connected:
|
case ConnectionStatus.connected:
|
||||||
statusString = 'Connected';
|
statusString = context.translations.connectedLabel;
|
||||||
showStatus = false;
|
showStatus = false;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.connecting:
|
case ConnectionStatus.connecting:
|
||||||
statusString = 'Reconnecting...';
|
statusString = context.translations.reconnectingLabel;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.disconnected:
|
case ConnectionStatus.disconnected:
|
||||||
statusString = 'Disconnected';
|
statusString = context.translations.disconnectedLabel;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:collection/collection.dart' show IterableExtension;
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget which shows channel info
|
/// Widget which shows channel info
|
||||||
class ChannelInfo extends StatelessWidget {
|
class ChannelInfo extends StatelessWidget {
|
||||||
@@ -55,10 +56,13 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
) {
|
) {
|
||||||
Widget? alternativeWidget;
|
Widget? alternativeWidget;
|
||||||
|
|
||||||
if (channel.memberCount != null && channel.memberCount! > 2) {
|
final memberCount = channel.memberCount;
|
||||||
var text = '${channel.memberCount} Members';
|
if (memberCount != null && memberCount > 2) {
|
||||||
|
var text = context.translations.membersCountText(memberCount);
|
||||||
final watcherCount = channel.state?.watcherCount ?? 0;
|
final watcherCount = channel.state?.watcherCount ?? 0;
|
||||||
if (watcherCount > 0) text += ' $watcherCount Online';
|
if (watcherCount > 0) {
|
||||||
|
text += ' ${context.translations.watchersCountText(watcherCount)}';
|
||||||
|
}
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
text,
|
text,
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
@@ -75,12 +79,13 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
if (otherMember != null) {
|
if (otherMember != null) {
|
||||||
if (otherMember.user?.online == true) {
|
if (otherMember.user?.online == true) {
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
'Online',
|
context.translations.userOnlineText,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
'Last seen ${Jiffy(otherMember.user?.lastActive).fromNow()}',
|
'${context.translations.userLastOnlineText} '
|
||||||
|
'${Jiffy(otherMember.user?.lastActive).fromNow()}',
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -111,7 +116,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
'Searching for Network',
|
context.translations.searchingForNetworkText,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -125,7 +130,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Offline...',
|
context.translations.offlineLabel,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -141,7 +146,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
..closeConnection()
|
..closeConnection()
|
||||||
..openConnection(),
|
..openConnection(),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Try Again',
|
context.translations.tryAgainLabel,
|
||||||
style: textStyle?.copyWith(
|
style: textStyle?.copyWith(
|
||||||
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart';
|
import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget builder for title
|
/// Widget builder for title
|
||||||
typedef TitleBuilder = Widget Function(
|
typedef TitleBuilder = Widget Function(
|
||||||
@@ -103,21 +104,20 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus.connected:
|
case ConnectionStatus.connected:
|
||||||
statusString = 'Connected';
|
statusString = context.translations.connectedLabel;
|
||||||
showStatus = false;
|
showStatus = false;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.connecting:
|
case ConnectionStatus.connecting:
|
||||||
statusString = 'Reconnecting...';
|
statusString = context.translations.reconnectingLabel;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.disconnected:
|
case ConnectionStatus.disconnected:
|
||||||
statusString = 'Disconnected';
|
statusString = context.translations.disconnectedLabel;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
return InfoTile(
|
return InfoTile(
|
||||||
// ignore: avoid_bool_literals_in_conditional_expressions
|
showMessage: showConnectionStateTile && showStatus,
|
||||||
showMessage: showConnectionStateTile ? showStatus : false,
|
|
||||||
message: statusString,
|
message: statusString,
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
textTheme: Theme.of(context).textTheme,
|
textTheme: Theme.of(context).textTheme,
|
||||||
@@ -207,7 +207,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
Widget _buildConnectedTitleState(BuildContext context) {
|
Widget _buildConnectedTitleState(BuildContext context) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
return Text(
|
return Text(
|
||||||
'Stream Chat',
|
context.translations.streamChatLabel,
|
||||||
style: chatThemeData.textTheme.headlineBold.copyWith(
|
style: chatThemeData.textTheme.headlineBold.copyWith(
|
||||||
color: chatThemeData.colorTheme.textHighEmphasis,
|
color: chatThemeData.colorTheme.textHighEmphasis,
|
||||||
),
|
),
|
||||||
@@ -226,7 +226,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
'Searching for Network',
|
context.translations.searchingForNetworkText,
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.channelListHeaderTheme
|
.channelListHeaderTheme
|
||||||
.title
|
.title
|
||||||
@@ -247,7 +247,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Offline...',
|
context.translations.offlineLabel,
|
||||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -258,7 +258,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
..closeConnection()
|
..closeConnection()
|
||||||
..openConnection(),
|
..openConnection(),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Try Again',
|
context.translations.tryAgainLabel,
|
||||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Callback called when tapping on a channel
|
/// Callback called when tapping on a channel
|
||||||
typedef ChannelTapCallback = void Function(Channel, Widget?);
|
typedef ChannelTapCallback = void Function(Channel, Widget?);
|
||||||
@@ -301,7 +302,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Let’s start chatting!',
|
context.translations.letsStartChattingLabel,
|
||||||
style: chatThemeData.textTheme.headline,
|
style: chatThemeData.textTheme.headline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -311,7 +312,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
horizontal: 52,
|
horizontal: 52,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'How about sending your first message to a friend?',
|
context.translations.sendingFirstMessageLabel,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: chatThemeData.textTheme.body.copyWith(
|
style: chatThemeData.textTheme.body.copyWith(
|
||||||
color: chatThemeData.colorTheme.textLowEmphasis,
|
color: chatThemeData.colorTheme.textLowEmphasis,
|
||||||
@@ -330,7 +331,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: widget.onStartChatPressed,
|
onPressed: widget.onStartChatPressed,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Start a chat',
|
context.translations.startAChatLabel,
|
||||||
style: chatThemeData.textTheme.bodyBold.copyWith(
|
style: chatThemeData.textTheme.bodyBold.copyWith(
|
||||||
color: chatThemeData.colorTheme.accentPrimary,
|
color: chatThemeData.colorTheme.accentPrimary,
|
||||||
),
|
),
|
||||||
@@ -466,9 +467,9 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text.rich(
|
Text.rich(
|
||||||
const TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
WidgetSpan(
|
const WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: 2,
|
right: 2,
|
||||||
@@ -476,14 +477,14 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
child: Icon(Icons.error_outline),
|
child: Icon(Icons.error_outline),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(text: 'Error loading channels'),
|
TextSpan(text: context.translations.loadingChannelsError),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
style: Theme.of(context).textTheme.headline6,
|
style: Theme.of(context).textTheme.headline6,
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => _channelListController.loadData!(),
|
onPressed: () => _channelListController.loadData!(),
|
||||||
child: const Text('Retry'),
|
child: Text(context.translations.retryLabel),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -561,17 +562,16 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
),
|
),
|
||||||
onTap: widget.onDeletePressed != null
|
onTap: widget.onDeletePressed != null
|
||||||
? () {
|
? () {
|
||||||
widget.onDeletePressed!(channel);
|
widget.onDeletePressed?.call(channel);
|
||||||
}
|
}
|
||||||
: () async {
|
: () async {
|
||||||
final res = await showConfirmationDialog(
|
final res = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
title: 'Delete Conversation',
|
title: context.translations.deleteConversationLabel,
|
||||||
okText: 'DELETE',
|
|
||||||
question:
|
question:
|
||||||
// ignore: lines_longer_than_80_chars
|
context.translations.deleteConversationQuestion,
|
||||||
'Are you sure you want to delete this conversation?',
|
okText: context.translations.deleteLabel,
|
||||||
cancelText: 'CANCEL',
|
cancelText: context.translations.cancelLabel,
|
||||||
icon: StreamSvgIcon.delete(
|
icon: StreamSvgIcon.delete(
|
||||||
color: chatThemeData.colorTheme.accentError,
|
color: chatThemeData.colorTheme.accentError,
|
||||||
),
|
),
|
||||||
@@ -668,7 +668,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Error loading channels',
|
context.translations.loadingChannelsError,
|
||||||
style: theme.textTheme.body.copyWith(
|
style: theme.textTheme.body.copyWith(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// It shows the current [Channel] name using a [Text] widget.
|
/// It shows the current [Channel] name using a [Text] widget.
|
||||||
///
|
///
|
||||||
@@ -44,8 +45,10 @@ class ChannelName extends StatelessWidget {
|
|||||||
) =>
|
) =>
|
||||||
LayoutBuilder(
|
LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
var title = 'No title';
|
var title = context.translations.noTitleText;
|
||||||
if (extraData['name'] == null) {
|
if (extraData['name'] != null) {
|
||||||
|
title = extraData['name'];
|
||||||
|
} else {
|
||||||
final otherMembers = members
|
final otherMembers = members
|
||||||
?.where((member) => member.userId != client.currentUser!.id);
|
?.where((member) => member.userId != client.currentUser!.id);
|
||||||
if (otherMembers?.length == 1) {
|
if (otherMembers?.length == 1) {
|
||||||
@@ -71,8 +74,6 @@ class ChannelName extends StatelessWidget {
|
|||||||
title = '${currentMembers.map((e) => e.user?.name).join(', ')} '
|
title = '${currentMembers.map((e) => e.user?.name).join(', ')} '
|
||||||
'${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}';
|
'${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
title = extraData['name'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:jiffy/jiffy.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
@@ -173,7 +174,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
startOfDay
|
startOfDay
|
||||||
.subtract(const Duration(days: 1))
|
.subtract(const Duration(days: 1))
|
||||||
.millisecondsSinceEpoch) {
|
.millisecondsSinceEpoch) {
|
||||||
stringDate = 'Yesterday';
|
stringDate = context.translations.yesterdayLabel;
|
||||||
} else if (startOfDay.difference(lastMessageAt).inDays < 7) {
|
} else if (startOfDay.difference(lastMessageAt).inDays < 7) {
|
||||||
stringDate = Jiffy(lastMessageAt.toLocal()).EEEE;
|
stringDate = Jiffy(lastMessageAt.toLocal()).EEEE;
|
||||||
} else {
|
} else {
|
||||||
@@ -198,7 +199,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
' Channel is muted',
|
' ${context.translations.channelIsMutedText}',
|
||||||
style: chatThemeData.channelPreviewTheme.subtitle,
|
style: chatThemeData.channelPreviewTheme.subtitle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// It shows a date divider depending on the date difference
|
/// It shows a date divider depending on the date difference
|
||||||
class DateDivider extends StatelessWidget {
|
class DateDivider extends StatelessWidget {
|
||||||
@@ -24,10 +25,10 @@ class DateDivider extends StatelessWidget {
|
|||||||
|
|
||||||
String dayInfo;
|
String dayInfo;
|
||||||
if (Jiffy(createdAt).isSame(now, Units.DAY)) {
|
if (Jiffy(createdAt).isSame(now, Units.DAY)) {
|
||||||
dayInfo = 'Today';
|
dayInfo = context.translations.todayLabel;
|
||||||
} else if (Jiffy(createdAt)
|
} else if (Jiffy(createdAt)
|
||||||
.isSame(now.subtract(const Duration(days: 1)), Units.DAY)) {
|
.isSame(now.subtract(const Duration(days: 1)), Units.DAY)) {
|
||||||
dayInfo = 'Yesterday';
|
dayInfo = context.translations.yesterdayLabel;
|
||||||
} else if (Jiffy(createdAt).isAfter(
|
} else if (Jiffy(createdAt).isAfter(
|
||||||
now.subtract(const Duration(days: 7)),
|
now.subtract(const Duration(days: 7)),
|
||||||
Units.DAY,
|
Units.DAY,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget to display deleted message
|
/// Widget to display deleted message
|
||||||
class DeletedMessage extends StatelessWidget {
|
class DeletedMessage extends StatelessWidget {
|
||||||
@@ -49,7 +50,7 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
horizontal: 16,
|
horizontal: 16,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Message deleted',
|
context.translations.messageDeletedLabel,
|
||||||
style: messageTheme.messageText?.copyWith(
|
style: messageTheme.messageText?.copyWith(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: messageTheme.createdAt?.color,
|
color: messageTheme.createdAt?.color,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:characters/characters.dart';
|
|||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/emoji/emoji.dart';
|
import 'package:stream_chat_flutter/src/emoji/emoji.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/localization/translations.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
final _emojiChars = Emoji.chars();
|
final _emojiChars = Emoji.chars();
|
||||||
@@ -9,7 +10,8 @@ final _emojiChars = Emoji.chars();
|
|||||||
/// String extension
|
/// String extension
|
||||||
extension StringExtension on String {
|
extension StringExtension on String {
|
||||||
/// Returns the capitalized string
|
/// Returns the capitalized string
|
||||||
String capitalize() => '${this[0].toUpperCase()}${substring(1)}';
|
String capitalize() =>
|
||||||
|
'${this[0].toUpperCase()}${substring(1).toLowerCase()}';
|
||||||
|
|
||||||
/// Returns whether the string contains only emoji's or not.
|
/// Returns whether the string contains only emoji's or not.
|
||||||
///
|
///
|
||||||
@@ -103,6 +105,11 @@ extension BuildContextX on BuildContext {
|
|||||||
// ignore: public_member_api_docs
|
// ignore: public_member_api_docs
|
||||||
double get textScaleFactor =>
|
double get textScaleFactor =>
|
||||||
MediaQuery.maybeOf(this)?.textScaleFactor ?? 1.0;
|
MediaQuery.maybeOf(this)?.textScaleFactor ?? 1.0;
|
||||||
|
|
||||||
|
/// Retrieves current translations according to locale
|
||||||
|
/// Defaults to [DefaultTranslations]
|
||||||
|
Translations get translations =>
|
||||||
|
StreamChatLocalizations.of(this) ?? DefaultTranslations.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extension on [BorderRadius]
|
/// Extension on [BorderRadius]
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import 'dart:io';
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
import 'package:stream_chat_flutter/src/gallery_footer.dart';
|
import 'package:stream_chat_flutter/src/gallery_footer.dart';
|
||||||
import 'package:stream_chat_flutter/src/gallery_header.dart';
|
import 'package:stream_chat_flutter/src/gallery_header.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Return action for coming back from pages
|
/// Return action for coming back from pages
|
||||||
enum ReturnActionType {
|
enum ReturnActionType {
|
||||||
@@ -182,9 +182,10 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
children: [
|
children: [
|
||||||
GalleryHeader(
|
GalleryHeader(
|
||||||
userName: widget.userName,
|
userName: widget.userName,
|
||||||
sentAt:
|
sentAt: context.translations.sentAtText(
|
||||||
// ignore: lines_longer_than_80_chars
|
date: widget.message.createdAt,
|
||||||
'Sent ${getDay(widget.message.createdAt.toLocal())} at ${Jiffy(widget.message.createdAt.toLocal()).format('HH:mm')}',
|
time: widget.message.createdAt,
|
||||||
|
),
|
||||||
onBackPressed: () {
|
onBackPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
@@ -197,7 +198,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (widget.message.type != 'ephemeral')
|
if (!widget.message.isEphemeral)
|
||||||
GalleryFooter(
|
GalleryFooter(
|
||||||
currentPage: _currentPage,
|
currentPage: _currentPage,
|
||||||
totalPages: widget.mediaAttachments.length,
|
totalPages: widget.mediaAttachments.length,
|
||||||
@@ -222,22 +223,6 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
String getDay(DateTime dateTime) {
|
|
||||||
final now = DateTime.now();
|
|
||||||
|
|
||||||
if (DateTime(dateTime.year, dateTime.month, dateTime.day) ==
|
|
||||||
DateTime(now.year, now.month, now.day)) {
|
|
||||||
return 'today';
|
|
||||||
} else if (DateTime(now.year, now.month, now.day)
|
|
||||||
.difference(dateTime)
|
|
||||||
.inHours <
|
|
||||||
24) {
|
|
||||||
return 'yesterday';
|
|
||||||
} else {
|
|
||||||
return 'on ${Jiffy(dateTime).MMMd}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() async {
|
void dispose() async {
|
||||||
for (final package in videoPackages.values) {
|
for (final package in videoPackages.values) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
|||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Footer widget for media display
|
/// Footer widget for media display
|
||||||
class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
|
class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
|
||||||
@@ -135,7 +136,9 @@ class _GalleryFooterState extends State<GalleryFooter> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
'${widget.currentPage + 1} of ${widget.totalPages}',
|
'${widget.currentPage + 1} '
|
||||||
|
'${context.translations.ofText} '
|
||||||
|
'${widget.totalPages}',
|
||||||
style: galleryFooterThemeData.titleTextStyle,
|
style: galleryFooterThemeData.titleTextStyle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -191,7 +194,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Photos',
|
context.translations.photosLabel,
|
||||||
style:
|
style:
|
||||||
galleryFooterThemeData.bottomSheetPhotosTextStyle,
|
galleryFooterThemeData.bottomSheetPhotosTextStyle,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
backgroundColor: galleryHeaderThemeData.backgroundColor,
|
backgroundColor: galleryHeaderThemeData.backgroundColor,
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
if (message.type != 'ephemeral')
|
if (!message.isEphemeral)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.iconMenuPoint(
|
icon: StreamSvgIcon.iconMenuPoint(
|
||||||
color: galleryHeaderThemeData.iconMenuPointColor,
|
color: galleryHeaderThemeData.iconMenuPointColor,
|
||||||
@@ -78,7 +78,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: message.type != 'ephemeral'
|
title: !message.isEphemeral
|
||||||
? InkWell(
|
? InkWell(
|
||||||
onTap: onTitleTap,
|
onTap: onTitleTap,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'package:stream_chat_flutter/src/localization/translations.dart'
|
||||||
|
show Translations;
|
||||||
|
|
||||||
|
/// Defines the localized resource values used by the StreamChatFlutter widgets.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [GlobalStreamChatLocalizations], which provides stream chat localizations
|
||||||
|
/// for many languages.
|
||||||
|
abstract class StreamChatLocalizations implements Translations {
|
||||||
|
/// The `StreamChatLocalizations` from the closest [Localizations] instance
|
||||||
|
/// that encloses the given context.
|
||||||
|
///
|
||||||
|
/// If no [StreamChatLocalizations] are available in the given `context`, this
|
||||||
|
/// method returns null.
|
||||||
|
///
|
||||||
|
/// This method is just a convenient shorthand for:
|
||||||
|
/// `Localizations.of<StreamChatLocalizations>(
|
||||||
|
/// context,
|
||||||
|
/// StreamChatLocalizations
|
||||||
|
/// )`.
|
||||||
|
///
|
||||||
|
/// References to the localized resources defined by this class are typically
|
||||||
|
/// written in terms of this method. For example:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// tooltip: StreamChatLocalizations.of(context).streamChatLabel,
|
||||||
|
/// ```
|
||||||
|
static StreamChatLocalizations? of(BuildContext context) =>
|
||||||
|
Localizations.of<StreamChatLocalizations>(
|
||||||
|
context,
|
||||||
|
StreamChatLocalizations,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,667 @@
|
|||||||
|
import 'package:jiffy/jiffy.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/connection_status_builder.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/message_input.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/message_list_view.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/message_search_list_view.dart';
|
||||||
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
|
show User;
|
||||||
|
|
||||||
|
/// Translation strings for the stream chat widgets
|
||||||
|
abstract class Translations {
|
||||||
|
/// The error shown when [launchURL] fails
|
||||||
|
String get launchUrlError;
|
||||||
|
|
||||||
|
/// The error shown when loading users fails
|
||||||
|
String get loadingUsersError;
|
||||||
|
|
||||||
|
/// The label for "retry" button
|
||||||
|
String get retryLabel;
|
||||||
|
|
||||||
|
/// The label for showing no users
|
||||||
|
String get noUsersLabel;
|
||||||
|
|
||||||
|
/// The text for showing user is online
|
||||||
|
String get userOnlineText;
|
||||||
|
|
||||||
|
/// The text for showing the last online of the user
|
||||||
|
String get userLastOnlineText;
|
||||||
|
|
||||||
|
/// The text shown when [users] starts typing
|
||||||
|
String userTypingText(Iterable<User> users);
|
||||||
|
|
||||||
|
/// The label for "thread reply"
|
||||||
|
String get threadReplyLabel;
|
||||||
|
|
||||||
|
/// The text for showing if the message is only visible to you
|
||||||
|
String get onlyVisibleToYouText;
|
||||||
|
|
||||||
|
/// The text for showing the thread reply count
|
||||||
|
String threadReplyCountText(int count);
|
||||||
|
|
||||||
|
/// The text for showing the attachments upload progress
|
||||||
|
String attachmentsUploadProgressText({
|
||||||
|
required int remaining,
|
||||||
|
required int total,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The text for showing who pinned the message
|
||||||
|
String pinnedByUserText({
|
||||||
|
required User pinnedBy,
|
||||||
|
required User currentUser,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The text for showing there are empty messages
|
||||||
|
String get emptyMessagesText;
|
||||||
|
|
||||||
|
/// The text for showing generic error
|
||||||
|
String get genericErrorText;
|
||||||
|
|
||||||
|
/// The error shown when loading messages fails
|
||||||
|
String get loadingMessagesError;
|
||||||
|
|
||||||
|
/// The text for showing the result count in [MessageSearchListView]
|
||||||
|
String resultCountText(int count);
|
||||||
|
|
||||||
|
/// The text for showing the message is deleted
|
||||||
|
String get messageDeletedText;
|
||||||
|
|
||||||
|
/// The label for message deleted
|
||||||
|
String get messageDeletedLabel;
|
||||||
|
|
||||||
|
/// The label for message reactions
|
||||||
|
String get messageReactionsLabel;
|
||||||
|
|
||||||
|
/// The text for showing there are no chats
|
||||||
|
String get emptyChatMessagesText;
|
||||||
|
|
||||||
|
/// The text for showing the thread separator in case [MessageListView]
|
||||||
|
/// contains a parent message
|
||||||
|
String threadSeparatorText(int replyCount);
|
||||||
|
|
||||||
|
/// The label for "connected" in [ConnectionStatusBuilder]
|
||||||
|
String get connectedLabel;
|
||||||
|
|
||||||
|
/// The label for "disconnected" in [ConnectionStatusBuilder]
|
||||||
|
String get disconnectedLabel;
|
||||||
|
|
||||||
|
/// The label for "reconnecting" in [ConnectionStatusBuilder]
|
||||||
|
String get reconnectingLabel;
|
||||||
|
|
||||||
|
/// The label for also send as direct message "checkbox"" in [MessageInput]
|
||||||
|
String get alsoSendAsDirectMessageLabel;
|
||||||
|
|
||||||
|
/// The label for search Gif
|
||||||
|
String get searchGifLabel;
|
||||||
|
|
||||||
|
/// The label for add a comment or send in case of
|
||||||
|
/// attachments inside [MessageInput]
|
||||||
|
String get addACommentOrSendLabel;
|
||||||
|
|
||||||
|
/// The label for write a message in [MessageInput]
|
||||||
|
String get writeAMessageLabel;
|
||||||
|
|
||||||
|
/// The label for instant commands in [MessageInput]
|
||||||
|
String get instantCommandsLabel;
|
||||||
|
|
||||||
|
/// The error shown in case the fi"le is too large even after compression
|
||||||
|
/// while uploading via [MessageInput]
|
||||||
|
String fileTooLargeAfterCompressionError(double limitInMB);
|
||||||
|
|
||||||
|
/// The error shown in case the file is too large
|
||||||
|
/// while uploading via [MessageInput]
|
||||||
|
String fileTooLargeError(double limitInMB);
|
||||||
|
|
||||||
|
/// The text for showing the query while searching for emojis
|
||||||
|
String emojiMatchingQueryText(String query);
|
||||||
|
|
||||||
|
/// The label for "add a file"
|
||||||
|
String get addAFileLabel;
|
||||||
|
|
||||||
|
/// The label for "upload a photo"
|
||||||
|
String get uploadAPhotoLabel;
|
||||||
|
|
||||||
|
/// The label for "upload a video"
|
||||||
|
String get uploadAVideoLabel;
|
||||||
|
|
||||||
|
/// The label for "photo from camera"
|
||||||
|
String get photoFromCameraLabel;
|
||||||
|
|
||||||
|
/// The label for "video from camera"
|
||||||
|
String get videoFromCameraLabel;
|
||||||
|
|
||||||
|
/// The label for "upload a file"
|
||||||
|
String get uploadAFileLabel;
|
||||||
|
|
||||||
|
/// The error shown when something went wrong
|
||||||
|
String get somethingWentWrongError;
|
||||||
|
|
||||||
|
/// The label for "OK"
|
||||||
|
String get okLabel;
|
||||||
|
|
||||||
|
/// The label for "add more files"
|
||||||
|
String get addMoreFilesLabel;
|
||||||
|
|
||||||
|
/// The message shown for asking photo and video access permission
|
||||||
|
String get enablePhotoAndVideoAccessMessage;
|
||||||
|
|
||||||
|
/// The message shown for asking gallery access permission
|
||||||
|
String get allowGalleryAccessMessage;
|
||||||
|
|
||||||
|
/// The label for "flag message"
|
||||||
|
String get flagMessageLabel;
|
||||||
|
|
||||||
|
/// The question asked while showing flag message dialog
|
||||||
|
String get flagMessageQuestion;
|
||||||
|
|
||||||
|
/// The label for "Flag"
|
||||||
|
String get flagLabel;
|
||||||
|
|
||||||
|
/// The label for "Cancel"
|
||||||
|
String get cancelLabel;
|
||||||
|
|
||||||
|
/// The label for successful message flag
|
||||||
|
String get flagMessageSuccessfulLabel;
|
||||||
|
|
||||||
|
/// The text for showing the message if successfully flagged
|
||||||
|
String get flagMessageSuccessfulText;
|
||||||
|
|
||||||
|
/// The label for "delete message"
|
||||||
|
String get deleteMessageLabel;
|
||||||
|
|
||||||
|
/// The question asked while showing delete message dialog
|
||||||
|
String get deleteMessageQuestion;
|
||||||
|
|
||||||
|
/// The label for "Delete"
|
||||||
|
String get deleteLabel;
|
||||||
|
|
||||||
|
/// The text for showing the operation could not be completed
|
||||||
|
String get operationCouldNotBeCompletedText;
|
||||||
|
|
||||||
|
/// The label for "Reply"
|
||||||
|
String get replyLabel;
|
||||||
|
|
||||||
|
/// The text for showing pin/un-pin functionality in [MessageWidget]
|
||||||
|
/// based on [pinned]
|
||||||
|
String togglePinUnpinText({required bool pinned});
|
||||||
|
|
||||||
|
/// The text for showing delete/retry-delete based on [isDeleteFailed]
|
||||||
|
String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed});
|
||||||
|
|
||||||
|
/// The label for "copy message"
|
||||||
|
String get copyMessageLabel;
|
||||||
|
|
||||||
|
/// The label for "edit message"
|
||||||
|
String get editMessageLabel;
|
||||||
|
|
||||||
|
/// The text for showing resend/resend-edited message
|
||||||
|
/// based on [isUpdateFailed]
|
||||||
|
String toggleResendOrResendEditedMessage({required bool isUpdateFailed});
|
||||||
|
|
||||||
|
/// The label for "Photos"
|
||||||
|
String get photosLabel;
|
||||||
|
|
||||||
|
/// The text for showing on which [date] and [time] the message was sent
|
||||||
|
String sentAtText({required DateTime date, required DateTime time});
|
||||||
|
|
||||||
|
/// The label for "Today"
|
||||||
|
String get todayLabel;
|
||||||
|
|
||||||
|
/// The label for "Yesterday"
|
||||||
|
String get yesterdayLabel;
|
||||||
|
|
||||||
|
/// The text for showing the channel is muted
|
||||||
|
String get channelIsMutedText;
|
||||||
|
|
||||||
|
/// The text for showing there is no title
|
||||||
|
String get noTitleText;
|
||||||
|
|
||||||
|
/// The label for "let's start chatting"
|
||||||
|
String get letsStartChattingLabel;
|
||||||
|
|
||||||
|
/// The label for sending the first message
|
||||||
|
String get sendingFirstMessageLabel;
|
||||||
|
|
||||||
|
/// The label for "start a chat"
|
||||||
|
String get startAChatLabel;
|
||||||
|
|
||||||
|
/// The error shown when loading channel fails
|
||||||
|
String get loadingChannelsError;
|
||||||
|
|
||||||
|
/// The label for "Delete conversation"
|
||||||
|
String get deleteConversationLabel;
|
||||||
|
|
||||||
|
/// The question asked while showing delete conversation dialog
|
||||||
|
String get deleteConversationQuestion;
|
||||||
|
|
||||||
|
/// The label for "Stream Chat"
|
||||||
|
String get streamChatLabel;
|
||||||
|
|
||||||
|
/// The text for showing searching for network
|
||||||
|
String get searchingForNetworkText;
|
||||||
|
|
||||||
|
/// The label for "Offline"
|
||||||
|
String get offlineLabel;
|
||||||
|
|
||||||
|
/// The label for "Try again"
|
||||||
|
String get tryAgainLabel;
|
||||||
|
|
||||||
|
/// The text for showing the members count based on [count]
|
||||||
|
String membersCountText(int count);
|
||||||
|
|
||||||
|
/// The text for showing the watchers count based on [count]
|
||||||
|
String watchersCountText(int count);
|
||||||
|
|
||||||
|
/// The label for "View Info"
|
||||||
|
String get viewInfoLabel;
|
||||||
|
|
||||||
|
/// The label for "Leave Group"
|
||||||
|
String get leaveGroupLabel;
|
||||||
|
|
||||||
|
/// The label for "Leave"
|
||||||
|
String get leaveLabel;
|
||||||
|
|
||||||
|
/// The label for "Leave conversation"
|
||||||
|
String get leaveConversationLabel;
|
||||||
|
|
||||||
|
/// The question asked while showing leave conversation dialog
|
||||||
|
String get leaveConversationQuestion;
|
||||||
|
|
||||||
|
/// The label for "Show in chat"
|
||||||
|
String get showInChatLabel;
|
||||||
|
|
||||||
|
/// The label for "Save Image"
|
||||||
|
String get saveImageLabel;
|
||||||
|
|
||||||
|
/// The label for "Save Video"
|
||||||
|
String get saveVideoLabel;
|
||||||
|
|
||||||
|
/// The label for "Upload Error"
|
||||||
|
String get uploadErrorLabel;
|
||||||
|
|
||||||
|
/// The label for "Giphy"
|
||||||
|
String get giphyLabel;
|
||||||
|
|
||||||
|
/// The label for "Shuffle"
|
||||||
|
String get shuffleLabel;
|
||||||
|
|
||||||
|
/// The label for "Send"
|
||||||
|
String get sendLabel;
|
||||||
|
|
||||||
|
/// The label for "With"
|
||||||
|
String get withText;
|
||||||
|
|
||||||
|
/// The text shown for "In"
|
||||||
|
String get inText;
|
||||||
|
|
||||||
|
/// The text shown for "You"
|
||||||
|
String get youText;
|
||||||
|
|
||||||
|
/// The text shown for "Of"
|
||||||
|
String get ofText;
|
||||||
|
|
||||||
|
/// The text shown for "File"
|
||||||
|
String get fileText;
|
||||||
|
|
||||||
|
/// The label for "Reply to message"
|
||||||
|
String get replyToMessageLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default implementation of Translation strings for the stream chat widgets
|
||||||
|
class DefaultTranslations implements Translations {
|
||||||
|
const DefaultTranslations._();
|
||||||
|
|
||||||
|
/// Singleton instance of [DefaultTranslations]
|
||||||
|
static const instance = DefaultTranslations._();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get launchUrlError => 'Cannot launch the url';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadingUsersError => 'Error loading users';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noUsersLabel => 'There are no users currently';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get retryLabel => 'Retry';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get userLastOnlineText => 'Last online';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get userOnlineText => 'Online';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String userTypingText(Iterable<User> users) {
|
||||||
|
if (users.isEmpty) return '';
|
||||||
|
final first = users.first;
|
||||||
|
if (users.length == 1) {
|
||||||
|
return '${first.name} is typing';
|
||||||
|
}
|
||||||
|
return '${first.name} and ${users.length - 1} more are typing';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get threadReplyLabel => 'Thread Reply';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get onlyVisibleToYouText => 'Only visible to you';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String threadReplyCountText(int count) => '$count Thread Replies';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String attachmentsUploadProgressText({
|
||||||
|
required int remaining,
|
||||||
|
required int total,
|
||||||
|
}) =>
|
||||||
|
'Uploading $remaining/$total ...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pinnedByUserText({
|
||||||
|
required User pinnedBy,
|
||||||
|
required User currentUser,
|
||||||
|
}) {
|
||||||
|
final pinnedByCurrentUser = currentUser.id == pinnedBy.id;
|
||||||
|
if (pinnedByCurrentUser) return 'Pinned by You';
|
||||||
|
return 'Pinned by ${pinnedBy.name}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyMessagesText => 'There are no messages currently';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get genericErrorText => 'Something went wrong';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadingMessagesError => 'Error loading messages';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String resultCountText(int count) => '$count results';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get messageDeletedText => 'This message is deleted.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get messageDeletedLabel => 'Message deleted';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get messageReactionsLabel => 'Message Reactions';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyChatMessagesText => 'No chats here yet...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String threadSeparatorText(int replyCount) {
|
||||||
|
if (replyCount == 1) return '1 Reply';
|
||||||
|
return '$replyCount Replies';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get connectedLabel => 'Connected';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get disconnectedLabel => 'Disconnected';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get reconnectingLabel => 'Reconnecting...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get alsoSendAsDirectMessageLabel => 'Also send as direct message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get addACommentOrSendLabel => 'Add a comment or send';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get searchGifLabel => 'Search GIFs';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get writeAMessageLabel => 'Write a message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get instantCommandsLabel => 'Instant Commands';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String fileTooLargeAfterCompressionError(double limitInMB) =>
|
||||||
|
'The file is too large to upload. '
|
||||||
|
'The file size limit is $limitInMB MB. '
|
||||||
|
'We tried compressing it, but it was not enough.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String fileTooLargeError(double limitInMB) =>
|
||||||
|
'The file is too large to upload. The file size limit is $limitInMB MB.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String emojiMatchingQueryText(String query) => 'Emoji matching "$query"';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get addAFileLabel => 'Add a file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get photoFromCameraLabel => 'Photo from camera';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get uploadAFileLabel => 'Upload a file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get uploadAPhotoLabel => 'Upload a photo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get uploadAVideoLabel => 'Upload a video';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get videoFromCameraLabel => 'Video from camera';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get okLabel => 'OK';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get somethingWentWrongError => 'Something went wrong';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get addMoreFilesLabel => 'Add more files';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get enablePhotoAndVideoAccessMessage =>
|
||||||
|
'Please enable access to your photos'
|
||||||
|
'\nand videos so you can share them with friends.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get allowGalleryAccessMessage => 'Allow access to your gallery';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flagMessageLabel => 'Flag Message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flagMessageQuestion =>
|
||||||
|
'Do you want to send a copy of this message to a'
|
||||||
|
'\nmoderator for further investigation?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flagLabel => 'FLAG';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cancelLabel => 'CANCEL';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flagMessageSuccessfulLabel => 'Message flagged';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flagMessageSuccessfulText =>
|
||||||
|
'The message has been reported to a moderator.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteLabel => 'DELETE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteMessageLabel => 'Delete Message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteMessageQuestion =>
|
||||||
|
'Are you sure you want to permanently delete this\nmessage?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get operationCouldNotBeCompletedText =>
|
||||||
|
'The operation couldn\'t be completed.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get replyLabel => 'Reply';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String togglePinUnpinText({required bool pinned}) {
|
||||||
|
if (pinned) return 'Unpin from Conversation';
|
||||||
|
return 'Pin to Conversation';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed}) {
|
||||||
|
if (isDeleteFailed) return 'Retry Deleting Message';
|
||||||
|
return 'Delete Message';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get copyMessageLabel => 'Copy Message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get editMessageLabel => 'Edit Message';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toggleResendOrResendEditedMessage({required bool isUpdateFailed}) {
|
||||||
|
if (isUpdateFailed) return 'Resend Edited Message';
|
||||||
|
return 'Resend';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get photosLabel => 'Photos';
|
||||||
|
|
||||||
|
String _getDay(DateTime dateTime) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final today = DateTime(now.year, now.month, now.day);
|
||||||
|
final yesterday = DateTime(now.year, now.month, now.day - 1);
|
||||||
|
|
||||||
|
final date = DateTime(dateTime.year, dateTime.month, dateTime.day);
|
||||||
|
|
||||||
|
if (date == today) {
|
||||||
|
return 'today';
|
||||||
|
} else if (date == yesterday) {
|
||||||
|
return 'yesterday';
|
||||||
|
} else {
|
||||||
|
return 'on ${Jiffy(date).MMMd}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String sentAtText({required DateTime date, required DateTime time}) =>
|
||||||
|
'Sent ${_getDay(date)} at ${Jiffy(time.toLocal()).format('HH:mm')}';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get todayLabel => 'Today';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get yesterdayLabel => 'Yesterday';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get channelIsMutedText => 'Channel is muted';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noTitleText => 'No title';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get letsStartChattingLabel => 'Let’s start chatting!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sendingFirstMessageLabel =>
|
||||||
|
'How about sending your first message to a friend?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get startAChatLabel => 'Start a chat';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadingChannelsError => 'Error loading channels';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteConversationLabel => 'Delete Conversation';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get deleteConversationQuestion =>
|
||||||
|
'Are you sure you want to delete this conversation?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get streamChatLabel => 'Stream Chat';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get searchingForNetworkText => 'Searching for Network';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get offlineLabel => 'Offline...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tryAgainLabel => 'Try Again';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String membersCountText(int count) {
|
||||||
|
if (count == 1) return '1 Member';
|
||||||
|
return '$count Members';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String watchersCountText(int count) {
|
||||||
|
if (count == 1) return '1 Online';
|
||||||
|
return '$count Online';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get viewInfoLabel => 'View Info';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get leaveGroupLabel => 'Leave Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get leaveLabel => 'LEAVE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get leaveConversationLabel => 'Leave conversation';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get leaveConversationQuestion =>
|
||||||
|
'Are you sure you want to leave this conversation?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get showInChatLabel => 'Show in Chat';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveImageLabel => 'Save Image';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveVideoLabel => 'Save Video';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get uploadErrorLabel => 'UPLOAD ERROR';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get giphyLabel => 'Giphy';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get shuffleLabel => 'Shuffle';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sendLabel => 'Send';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get withText => 'with';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get inText => 'in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get youText => 'You';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ofText => 'of';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get fileText => 'File';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get replyToMessageLabel => 'Reply to Message';
|
||||||
|
}
|
||||||
@@ -268,16 +268,14 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
final streamChatThemeData = StreamChatTheme.of(context);
|
final streamChatThemeData = StreamChatTheme.of(context);
|
||||||
final answer = await showConfirmationDialog(
|
final answer = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
title: 'Flag Message',
|
title: context.translations.flagMessageLabel,
|
||||||
icon: StreamSvgIcon.flag(
|
icon: StreamSvgIcon.flag(
|
||||||
color: streamChatThemeData.colorTheme.accentError,
|
color: streamChatThemeData.colorTheme.accentError,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
question:
|
question: context.translations.flagMessageQuestion,
|
||||||
// ignore: lines_longer_than_80_chars
|
okText: context.translations.flagLabel,
|
||||||
'Do you want to send a copy of this message to a\nmoderator for further investigation?',
|
cancelText: context.translations.cancelLabel,
|
||||||
okText: 'FLAG',
|
|
||||||
cancelText: 'CANCEL',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final theme = streamChatThemeData;
|
final theme = streamChatThemeData;
|
||||||
@@ -290,9 +288,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
color: theme.colorTheme.accentError,
|
color: theme.colorTheme.accentError,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
details: 'The message has been reported to a moderator.',
|
details: context.translations.flagMessageSuccessfulText,
|
||||||
title: 'Message flagged',
|
title: context.translations.flagMessageSuccessfulLabel,
|
||||||
okText: 'OK',
|
okText: context.translations.okLabel,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is StreamChatNetworkError &&
|
if (err is StreamChatNetworkError &&
|
||||||
@@ -303,9 +301,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
color: theme.colorTheme.accentError,
|
color: theme.colorTheme.accentError,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
details: 'The message has been reported to a moderator.',
|
details: context.translations.flagMessageSuccessfulText,
|
||||||
title: 'Message flagged',
|
title: context.translations.flagMessageSuccessfulLabel,
|
||||||
okText: 'OK',
|
okText: context.translations.okLabel,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_showErrorAlert();
|
_showErrorAlert();
|
||||||
@@ -335,14 +333,14 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
});
|
});
|
||||||
final answer = await showConfirmationDialog(
|
final answer = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
title: 'Delete message',
|
title: context.translations.deleteMessageLabel,
|
||||||
icon: StreamSvgIcon.flag(
|
icon: StreamSvgIcon.flag(
|
||||||
color: StreamChatTheme.of(context).colorTheme.accentError,
|
color: StreamChatTheme.of(context).colorTheme.accentError,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
question: 'Are you sure you want to permanently delete this\nmessage?',
|
question: context.translations.deleteMessageQuestion,
|
||||||
okText: 'DELETE',
|
okText: context.translations.deleteLabel,
|
||||||
cancelText: 'CANCEL',
|
cancelText: context.translations.cancelLabel,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (answer == true) {
|
if (answer == true) {
|
||||||
@@ -366,9 +364,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
color: StreamChatTheme.of(context).colorTheme.accentError,
|
color: StreamChatTheme.of(context).colorTheme.accentError,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
details: 'The operation couldn\'t be completed.',
|
details: context.translations.operationCouldNotBeCompletedText,
|
||||||
title: 'Something went wrong',
|
title: context.translations.somethingWentWrongError,
|
||||||
okText: 'OK',
|
okText: context.translations.okLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +388,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Reply',
|
context.translations.replyLabel,
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -412,7 +410,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Flag Message',
|
context.translations.flagMessageLabel,
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -435,7 +433,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'${widget.message.pinned ? 'Unpin from' : 'Pin to'} Conversation',
|
context.translations.togglePinUnpinText(
|
||||||
|
pinned: widget.message.pinned,
|
||||||
|
),
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -458,7 +458,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
isDeleteFailed ? 'Retry Deleting Message' : 'Delete Message',
|
context.translations.toggleDeleteRetryDeleteMessageText(
|
||||||
|
isDeleteFailed: isDeleteFailed,
|
||||||
|
),
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.body
|
.body
|
||||||
@@ -487,7 +489,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Copy Message',
|
context.translations.copyMessageLabel,
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -512,7 +514,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Edit Message',
|
context.translations.editMessageLabel,
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -544,7 +546,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
isUpdateFailed ? 'Resend Edited Message' : 'Resend',
|
context.translations.toggleResendOrResendEditedMessage(
|
||||||
|
isUpdateFailed: isUpdateFailed,
|
||||||
|
),
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -588,9 +592,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
color: streamChatThemeData.colorTheme.disabled,
|
color: streamChatThemeData.colorTheme.disabled,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Text(
|
Text(
|
||||||
'Edit Message',
|
context.translations.editMessageLabel,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
@@ -636,7 +640,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Thread Reply',
|
context.translations.threadReplyLabel,
|
||||||
style: streamChatThemeData.textTheme.body,
|
style: streamChatThemeData.textTheme.body,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -357,9 +357,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
color: _streamChatTheme.colorTheme.disabled,
|
color: _streamChatTheme.colorTheme.disabled,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Text(
|
Text(
|
||||||
'Reply to Message',
|
context.translations.replyToMessageLabel,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
@@ -461,7 +461,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Also send as direct message',
|
context.translations.alsoSendAsDirectMessageLabel,
|
||||||
style: _streamChatTheme.textTheme.footnote.copyWith(
|
style: _streamChatTheme.textTheme.footnote.copyWith(
|
||||||
color: _streamChatTheme.colorTheme.textHighEmphasis
|
color: _streamChatTheme.colorTheme.textHighEmphasis
|
||||||
.withOpacity(0.5),
|
.withOpacity(0.5),
|
||||||
@@ -586,7 +586,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
style: _streamChatTheme.messageInputTheme.inputTextStyle,
|
style: _streamChatTheme.messageInputTheme.inputTextStyle,
|
||||||
autofocus: widget.autofocus,
|
autofocus: widget.autofocus,
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
decoration: _getInputDecoration(),
|
decoration: _getInputDecoration(context),
|
||||||
textCapitalization: TextCapitalization.sentences,
|
textCapitalization: TextCapitalization.sentences,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -598,11 +598,11 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDecoration _getInputDecoration() {
|
InputDecoration _getInputDecoration(BuildContext context) {
|
||||||
final passedDecoration = _streamChatTheme.messageInputTheme.inputDecoration;
|
final passedDecoration = _streamChatTheme.messageInputTheme.inputDecoration;
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
hintText: _getHint(),
|
hintText: _getHint(context),
|
||||||
hintStyle: _streamChatTheme.messageInputTheme.inputTextStyle!.copyWith(
|
hintStyle: _streamChatTheme.messageInputTheme.inputTextStyle!.copyWith(
|
||||||
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
@@ -751,14 +751,14 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getHint() {
|
String _getHint(BuildContext context) {
|
||||||
if (_commandEnabled && _chosenCommand!.name == 'giphy') {
|
if (_commandEnabled && _chosenCommand!.name == 'giphy') {
|
||||||
return 'Search GIFs';
|
return context.translations.searchGifLabel;
|
||||||
}
|
}
|
||||||
if (_attachments.isNotEmpty) {
|
if (_attachments.isNotEmpty) {
|
||||||
return 'Add a comment or send';
|
return context.translations.addACommentOrSendLabel;
|
||||||
}
|
}
|
||||||
return 'Write a message';
|
return context.translations.writeAMessageLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _checkEmoji(String s, BuildContext context) {
|
void _checkEmoji(String s, BuildContext context) {
|
||||||
@@ -881,7 +881,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Instant Commands',
|
context.translations.instantCommandsLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _streamChatTheme.colorTheme.textHighEmphasis
|
color: _streamChatTheme.colorTheme.textHighEmphasis
|
||||||
.withOpacity(.5),
|
.withOpacity(.5),
|
||||||
@@ -1144,8 +1144,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
||||||
_showErrorAlert(
|
_showErrorAlert(
|
||||||
// ignore: lines_longer_than_80_chars
|
context.translations.fileTooLargeAfterCompressionError(
|
||||||
'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.',
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1156,9 +1157,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
path: mediaInfo.path,
|
path: mediaInfo.path,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_showErrorAlert(
|
_showErrorAlert(context.translations.fileTooLargeError(
|
||||||
'The file is too large to upload. The file size limit is 20MB.',
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1426,7 +1427,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Emoji matching "$query"',
|
context.translations.emojiMatchingQueryText(
|
||||||
|
query,
|
||||||
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _streamChatTheme
|
color: _streamChatTheme
|
||||||
.colorTheme.textHighEmphasis
|
.colorTheme.textHighEmphasis
|
||||||
@@ -1776,17 +1779,17 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
builder: (_) => Column(
|
builder: (_) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
'Add a file',
|
context.translations.addAFileLabel,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.image),
|
leading: const Icon(Icons.image),
|
||||||
title: const Text('Upload a photo'),
|
title: Text(context.translations.uploadAPhotoLabel),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
pickFile(DefaultAttachmentTypes.image);
|
pickFile(DefaultAttachmentTypes.image);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -1794,7 +1797,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.video_library),
|
leading: const Icon(Icons.video_library),
|
||||||
title: const Text('Upload a video'),
|
title: Text(context.translations.uploadAVideoLabel),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
pickFile(DefaultAttachmentTypes.video);
|
pickFile(DefaultAttachmentTypes.video);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -1803,7 +1806,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
if (!kIsWeb)
|
if (!kIsWeb)
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.camera_alt),
|
leading: const Icon(Icons.camera_alt),
|
||||||
title: const Text('Photo from camera'),
|
title: Text(context.translations.photoFromCameraLabel),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
pickFile(DefaultAttachmentTypes.image, true);
|
pickFile(DefaultAttachmentTypes.image, true);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -1812,7 +1815,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
if (!kIsWeb)
|
if (!kIsWeb)
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.videocam),
|
leading: const Icon(Icons.videocam),
|
||||||
title: const Text('Video from camera'),
|
title: Text(context.translations.videoFromCameraLabel),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
pickFile(DefaultAttachmentTypes.video, true);
|
pickFile(DefaultAttachmentTypes.video, true);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -1820,7 +1823,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.insert_drive_file),
|
leading: const Icon(Icons.insert_drive_file),
|
||||||
title: const Text('Upload a file'),
|
title: Text(context.translations.uploadAFileLabel),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
pickFile(DefaultAttachmentTypes.file);
|
pickFile(DefaultAttachmentTypes.file);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -1923,8 +1926,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
||||||
_showErrorAlert(
|
_showErrorAlert(
|
||||||
// ignore: lines_longer_than_80_chars
|
context.translations.fileTooLargeAfterCompressionError(
|
||||||
'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.',
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1935,9 +1939,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
path: mediaInfo.path,
|
path: mediaInfo.path,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_showErrorAlert(
|
_showErrorAlert(context.translations.fileTooLargeError(
|
||||||
'The file is too large to upload. The file size limit is 20MB.',
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2117,7 +2121,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
height: 26,
|
height: 26,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Something went wrong',
|
context.translations.somethingWentWrongError,
|
||||||
style: _streamChatTheme.textTheme.headlineBold,
|
style: _streamChatTheme.textTheme.headlineBold,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@@ -2146,7 +2150,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'OK',
|
context.translations.okLabel,
|
||||||
style: _streamChatTheme.textTheme.bodyBold.copyWith(
|
style: _streamChatTheme.textTheme.bodyBold.copyWith(
|
||||||
color: _streamChatTheme.colorTheme.accentPrimary),
|
color: _streamChatTheme.colorTheme.accentPrimary),
|
||||||
),
|
),
|
||||||
@@ -2257,10 +2261,10 @@ class _PickerWidget extends StatefulWidget {
|
|||||||
final StreamChatThemeData streamChatTheme;
|
final StreamChatThemeData streamChatTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
__PickerWidgetState createState() => __PickerWidgetState();
|
_PickerWidgetState createState() => _PickerWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class __PickerWidgetState extends State<_PickerWidget> {
|
class _PickerWidgetState extends State<_PickerWidget> {
|
||||||
Future<bool>? requestPermission;
|
Future<bool>? requestPermission;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -2292,7 +2296,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
|
|||||||
color: widget.streamChatTheme.colorTheme.inputBg,
|
color: widget.streamChatTheme.colorTheme.inputBg,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Add more files',
|
context.translations.addMoreFilesLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: widget.streamChatTheme.colorTheme.accentPrimary,
|
color: widget.streamChatTheme.colorTheme.accentPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -2324,8 +2328,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
|
|||||||
color: widget.streamChatTheme.colorTheme.disabled,
|
color: widget.streamChatTheme.colorTheme.disabled,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
// ignore: lines_longer_than_80_chars
|
context.translations.enablePhotoAndVideoAccessMessage,
|
||||||
'Please enable access to your photos \nand videos so you can share them with friends.',
|
|
||||||
style: widget.streamChatTheme.textTheme.body.copyWith(
|
style: widget.streamChatTheme.textTheme.body.copyWith(
|
||||||
color:
|
color:
|
||||||
widget.streamChatTheme.colorTheme.textLowEmphasis),
|
widget.streamChatTheme.colorTheme.textLowEmphasis),
|
||||||
@@ -2334,7 +2337,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
|
|||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Allow access to your gallery',
|
context.translations.allowGalleryAccessMessage,
|
||||||
style: widget.streamChatTheme.textTheme.bodyBold.copyWith(
|
style: widget.streamChatTheme.textTheme.bodyBold.copyWith(
|
||||||
color: widget.streamChatTheme.colorTheme.accentPrimary,
|
color: widget.streamChatTheme.colorTheme.accentPrimary,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
bool _inBetweenList = false;
|
bool _inBetweenList = false;
|
||||||
|
|
||||||
late final _defaultController = MessageListController();
|
late final _defaultController = MessageListController();
|
||||||
|
|
||||||
MessageListController get _messageListController =>
|
MessageListController get _messageListController =>
|
||||||
widget.messageListController ?? _defaultController;
|
widget.messageListController ?? _defaultController;
|
||||||
|
|
||||||
@@ -349,7 +350,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
emptyBuilder: widget.emptyBuilder ??
|
emptyBuilder: widget.emptyBuilder ??
|
||||||
(context) => Center(
|
(context) => Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'No chats here yet...',
|
context.translations.emptyChatMessagesText,
|
||||||
style: _streamTheme.textTheme.footnote.copyWith(
|
style: _streamTheme.textTheme.footnote.copyWith(
|
||||||
color: _streamTheme.colorTheme.textHighEmphasis
|
color: _streamTheme.colorTheme.textHighEmphasis
|
||||||
.withOpacity(.5)),
|
.withOpacity(.5)),
|
||||||
@@ -362,7 +363,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
errorBuilder: widget.errorBuilder ??
|
errorBuilder: widget.errorBuilder ??
|
||||||
(BuildContext context, Object error) => Center(
|
(BuildContext context, Object error) => Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Something went wrong',
|
context.translations.genericErrorText,
|
||||||
style: _streamTheme.textTheme.footnote.copyWith(
|
style: _streamTheme.textTheme.footnote.copyWith(
|
||||||
color: _streamTheme.colorTheme.textHighEmphasis
|
color: _streamTheme.colorTheme.textHighEmphasis
|
||||||
.withOpacity(.5)),
|
.withOpacity(.5)),
|
||||||
@@ -408,14 +409,14 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
var showStatus = true;
|
var showStatus = true;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus.connected:
|
case ConnectionStatus.connected:
|
||||||
statusString = 'Connected';
|
statusString = context.translations.connectedLabel;
|
||||||
showStatus = false;
|
showStatus = false;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.connecting:
|
case ConnectionStatus.connecting:
|
||||||
statusString = 'Reconnecting...';
|
statusString = context.translations.reconnectingLabel;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.disconnected:
|
case ConnectionStatus.disconnected:
|
||||||
statusString = 'Disconnected';
|
statusString = context.translations.disconnectedLabel;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +618,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
return widget.threadSeparatorBuilder!.call(context);
|
return widget.threadSeparatorBuilder!.call(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
final replyCount = widget.parentMessage!.replyCount;
|
final replyCount = widget.parentMessage!.replyCount!;
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: _streamTheme.colorTheme.bgGradient,
|
gradient: _streamTheme.colorTheme.bgGradient,
|
||||||
@@ -625,7 +626,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
'$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}',
|
context.translations.threadSeparatorText(replyCount),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: _streamTheme.channelTheme.channelHeaderTheme.subtitle,
|
style: _streamTheme.channelTheme.channelHeaderTheme.subtitle,
|
||||||
),
|
),
|
||||||
@@ -1249,8 +1250,8 @@ class _LoadingIndicator extends StatelessWidget {
|
|||||||
initialData: false,
|
initialData: false,
|
||||||
errorBuilder: (context, error) => Container(
|
errorBuilder: (context, error) => Container(
|
||||||
color: streamTheme.colorTheme.accentError.withOpacity(.2),
|
color: streamTheme.colorTheme.accentError.withOpacity(.2),
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Text('Error loading messages'),
|
child: Text(context.translations.loadingMessagesError),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
builder: (context, data) {
|
builder: (context, data) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:stream_chat_flutter/src/stream_chat.dart';
|
|||||||
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Modal widget for displaying message reactions
|
/// Modal widget for displaying message reactions
|
||||||
class MessageReactionsModal extends StatelessWidget {
|
class MessageReactionsModal extends StatelessWidget {
|
||||||
@@ -154,7 +155,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Message Reactions',
|
context.translations.messageReactionsLabel,
|
||||||
style: chatThemeData.textTheme.headlineBold,
|
style: chatThemeData.textTheme.headlineBold,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// It shows the current [Message] preview.
|
/// It shows the current [Message] preview.
|
||||||
///
|
///
|
||||||
@@ -50,13 +51,13 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
user.id == StreamChat.of(context).currentUser?.id
|
user.id == StreamChat.of(context).currentUser?.id
|
||||||
? 'You'
|
? context.translations.youText
|
||||||
: user.name,
|
: user.name,
|
||||||
style: chatThemeData.channelPreviewTheme.title,
|
style: chatThemeData.channelPreviewTheme.title,
|
||||||
),
|
),
|
||||||
if (channelName != null) ...[
|
if (channelName != null) ...[
|
||||||
Text(
|
Text(
|
||||||
' in ',
|
' ${context.translations.inText} ',
|
||||||
style: chatThemeData.channelPreviewTheme.title?.copyWith(
|
style: chatThemeData.channelPreviewTheme.title?.copyWith(
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
@@ -100,7 +101,7 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
Widget _buildSubtitle(BuildContext context, Message message) {
|
Widget _buildSubtitle(BuildContext context, Message message) {
|
||||||
var text = message.text;
|
var text = message.text;
|
||||||
if (message.isDeleted) {
|
if (message.isDeleted) {
|
||||||
text = 'This message was deleted.';
|
text = context.translations.messageDeletedText;
|
||||||
} else if (message.attachments.isNotEmpty) {
|
} else if (message.attachments.isNotEmpty) {
|
||||||
final parts = <String>[
|
final parts = <String>[
|
||||||
...message.attachments.map((e) {
|
...message.attachments.map((e) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:stream_chat_flutter/src/info_tile.dart';
|
|||||||
import 'package:stream_chat_flutter/src/message_search_item.dart';
|
import 'package:stream_chat_flutter/src/message_search_item.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Callback called when tapping on a user
|
/// Callback called when tapping on a user
|
||||||
typedef MessageSearchItemTapCallback = void Function(GetMessageResponse);
|
typedef MessageSearchItemTapCallback = void Function(GetMessageResponse);
|
||||||
@@ -140,6 +141,7 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
|
|
||||||
class _MessageSearchListViewState extends State<MessageSearchListView> {
|
class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||||
late final _defaultController = MessageSearchListController();
|
late final _defaultController = MessageSearchListController();
|
||||||
|
|
||||||
MessageSearchListController get _messageSearchListController =>
|
MessageSearchListController get _messageSearchListController =>
|
||||||
widget.messageSearchListController ?? _defaultController;
|
widget.messageSearchListController ?? _defaultController;
|
||||||
|
|
||||||
@@ -161,8 +163,8 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minHeight: viewportConstraints.maxHeight,
|
minHeight: viewportConstraints.maxHeight,
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Text('There are no messages currently'),
|
child: Text(context.translations.emptyMessagesText),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -176,7 +178,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
showMessage: widget.showErrorTile,
|
showMessage: widget.showErrorTile,
|
||||||
tileAnchor: Alignment.topCenter,
|
tileAnchor: Alignment.topCenter,
|
||||||
childAnchor: Alignment.topCenter,
|
childAnchor: Alignment.topCenter,
|
||||||
message: 'An error occurred.',
|
message: context.translations.genericErrorText,
|
||||||
child: Container(),
|
child: Container(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -240,10 +242,10 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
.colorTheme
|
.colorTheme
|
||||||
.accentError
|
.accentError
|
||||||
.withOpacity(.2),
|
.withOpacity(.2),
|
||||||
child: const Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text('Error loading messages'),
|
child: Text(context.translations.loadingMessagesError),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -306,7 +308,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
horizontal: 8,
|
horizontal: 8,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${items.length} results',
|
context.translations.resultCountText(items.length),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: chatThemeData.colorTheme.textLowEmphasis,
|
color: chatThemeData.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -51,15 +51,10 @@ class MessageText extends StatelessWidget {
|
|||||||
final mentionedUser = message.mentionedUsers.firstWhereOrNull(
|
final mentionedUser = message.mentionedUsers.firstWhereOrNull(
|
||||||
(u) => '@${u.name}' == link,
|
(u) => '@${u.name}' == link,
|
||||||
);
|
);
|
||||||
if (mentionedUser == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onMentionTap != null) {
|
if (mentionedUser == null) return;
|
||||||
onMentionTap!(mentionedUser);
|
|
||||||
} else {
|
onMentionTap?.call(mentionedUser);
|
||||||
print('tap on ${mentionedUser.name}');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (onLinkTap != null) {
|
if (onLinkTap != null) {
|
||||||
onLinkTap!(link);
|
onLinkTap!(link);
|
||||||
|
|||||||
@@ -860,9 +860,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
||||||
final replyCount = widget.message.replyCount;
|
final replyCount = widget.message.replyCount;
|
||||||
|
|
||||||
var msg = 'Thread Reply';
|
var msg = context.translations.threadReplyLabel;
|
||||||
if (showThreadReplyIndicator && replyCount! > 1) {
|
if (showThreadReplyIndicator && replyCount! > 1) {
|
||||||
msg = '$replyCount Thread Replies';
|
msg = context.translations.threadReplyCountText(replyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: prefer_function_declarations_over_variables
|
// ignore: prefer_function_declarations_over_variables
|
||||||
@@ -1207,7 +1207,10 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Text(
|
return Text(
|
||||||
'Uploading $uploadRemaining/$totalAttachments ...',
|
context.translations.attachmentsUploadProgressText(
|
||||||
|
remaining: uploadRemaining,
|
||||||
|
total: totalAttachments,
|
||||||
|
),
|
||||||
style: style,
|
style: style,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1281,8 +1284,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPinnedMessage(Message message) {
|
Widget _buildPinnedMessage(Message message) {
|
||||||
final pinnedBy = message.pinnedBy;
|
final pinnedBy = message.pinnedBy!;
|
||||||
final pinnedByMe = _streamChat.currentUser!.id == pinnedBy!.id;
|
final currentUser = _streamChat.currentUser!;
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 8),
|
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 8),
|
||||||
@@ -1296,7 +1299,10 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
width: 4,
|
width: 4,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Pinned by ${pinnedByMe ? 'You' : pinnedBy.name}',
|
context.translations.pinnedByUserText(
|
||||||
|
pinnedBy: pinnedBy,
|
||||||
|
currentUser: currentUser,
|
||||||
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
|
|||||||
@@ -146,15 +146,14 @@ class StreamChatState extends State<StreamChat> {
|
|||||||
/// The current user as a stream
|
/// The current user as a stream
|
||||||
Stream<User?> get currentUserStream => widget.client.state.currentUserStream;
|
Stream<User?> get currentUserStream => widget.client.state.currentUserStream;
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
final locale = ui.window.locale;
|
final locale = ui.window.locale;
|
||||||
Jiffy.locale(locale.languageCode);
|
final languageCode = locale.languageCode;
|
||||||
|
final availableLocales = Jiffy.getAllAvailableLocales();
|
||||||
|
if (availableLocales.contains(languageCode)) {
|
||||||
|
Jiffy.locale(languageCode);
|
||||||
|
}
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ class SystemMessage extends StatelessWidget {
|
|||||||
/// This message
|
/// This message
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
// ignore: lines_longer_than_80_chars
|
/// The function called when tapping on the message
|
||||||
/// The function called when tapping on the message when the message is not failed
|
/// when the message is not failed
|
||||||
final void Function(Message)? onMessageTap;
|
final void Function(Message)? onMessageTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
@@ -111,7 +112,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'with ',
|
'${context.translations.withText} ',
|
||||||
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
@@ -149,7 +150,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
children: [
|
children: [
|
||||||
title ??
|
title ??
|
||||||
Text(
|
Text(
|
||||||
'Thread Reply',
|
context.translations.threadReplyLabel,
|
||||||
style: chatThemeData.channelTheme.channelHeaderTheme.title,
|
style: chatThemeData.channelTheme.channelHeaderTheme.title,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lottie/lottie.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget to show the current list of typing users
|
/// Widget to show the current list of typing users
|
||||||
class TypingIndicator extends StatelessWidget {
|
class TypingIndicator extends StatelessWidget {
|
||||||
@@ -63,8 +64,7 @@ class TypingIndicator extends StatelessWidget {
|
|||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
// ignore: lines_longer_than_80_chars
|
context.translations.userTypingText(data),
|
||||||
' ${data.elementAt(0).name}${data.length == 1 ? '' : ' and ${data.length - 1} more'} ${data.length == 1 ? 'is' : 'are'} typing',
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
|||||||
import 'package:stream_chat_flutter/src/user_list_view.dart';
|
import 'package:stream_chat_flutter/src/user_list_view.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
/// It shows the current [User] preview.
|
/// It shows the current [User] preview.
|
||||||
@@ -86,12 +87,13 @@ class UserItem extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLastActive(context) {
|
Widget _buildLastActive(BuildContext context) {
|
||||||
final chatTheme = StreamChatTheme.of(context);
|
final chatTheme = StreamChatTheme.of(context);
|
||||||
return Text(
|
return Text(
|
||||||
user.online == true
|
user.online == true
|
||||||
? 'Online'
|
? context.translations.userOnlineText
|
||||||
: 'Last online ${Jiffy(user.lastActive).fromNow()}',
|
: '${context.translations.userLastOnlineText} '
|
||||||
|
'${Jiffy(user.lastActive).fromNow()}',
|
||||||
style: chatTheme.textTheme.footnote.copyWith(
|
style: chatTheme.textTheme.footnote.copyWith(
|
||||||
color: chatTheme.colorTheme.textHighEmphasis.withOpacity(.5)),
|
color: chatTheme.colorTheme.textHighEmphasis.withOpacity(.5)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Callback called when tapping on a user
|
/// Callback called when tapping on a user
|
||||||
typedef UserTapCallback = void Function(User, Widget?);
|
typedef UserTapCallback = void Function(User, Widget?);
|
||||||
@@ -155,6 +156,7 @@ class _UserListViewState extends State<UserListView>
|
|||||||
bool get _isListView => widget.crossAxisCount == 1;
|
bool get _isListView => widget.crossAxisCount == 1;
|
||||||
|
|
||||||
late final _defaultController = UserListController();
|
late final _defaultController = UserListController();
|
||||||
|
|
||||||
UserListController get _userListController =>
|
UserListController get _userListController =>
|
||||||
widget.userListController ?? _defaultController;
|
widget.userListController ?? _defaultController;
|
||||||
|
|
||||||
@@ -220,9 +222,9 @@ class _UserListViewState extends State<UserListView>
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text.rich(
|
Text.rich(
|
||||||
const TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
WidgetSpan(
|
const WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: 2,
|
right: 2,
|
||||||
@@ -230,14 +232,14 @@ class _UserListViewState extends State<UserListView>
|
|||||||
child: Icon(Icons.error_outline),
|
child: Icon(Icons.error_outline),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(text: 'Error loading users'),
|
TextSpan(text: context.translations.loadingUsersError),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
style: Theme.of(context).textTheme.headline6,
|
style: Theme.of(context).textTheme.headline6,
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => _userListController.loadData!(),
|
onPressed: () => _userListController.loadData!(),
|
||||||
child: const Text('Retry'),
|
child: Text(context.translations.retryLabel),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -250,8 +252,8 @@ class _UserListViewState extends State<UserListView>
|
|||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minHeight: viewportConstraints.maxHeight,
|
minHeight: viewportConstraints.maxHeight,
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Text('There are no users currently'),
|
child: Text(context.translations.noUsersLabel),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -400,10 +402,10 @@ class _UserListViewState extends State<UserListView>
|
|||||||
.colorTheme
|
.colorTheme
|
||||||
.accentError
|
.accentError
|
||||||
.withOpacity(.2),
|
.withOpacity(.2),
|
||||||
child: const Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text('Error loading users'),
|
child: Text(context.translations.loadingUsersError),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,17 +4,15 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Launch URL
|
/// Launch URL
|
||||||
Future<void> launchURL(BuildContext context, String? url) async {
|
Future<void> launchURL(BuildContext context, String? url) async {
|
||||||
if (url != null && await canLaunch(url)) {
|
if (url != null && await canLaunch(url)) {
|
||||||
await launch(url);
|
await launch(url);
|
||||||
} else {
|
} else {
|
||||||
// ignore: deprecated_member_use
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
Scaffold.of(context).showSnackBar(
|
SnackBar(content: Text(context.translations.launchUrlError)),
|
||||||
const SnackBar(
|
|
||||||
content: Text('Cannot launch the url'),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|
||||||
/// Widget for displaying a footnote
|
/// Widget for displaying a footnote
|
||||||
class VisibleFootnote extends StatelessWidget {
|
class VisibleFootnote extends StatelessWidget {
|
||||||
@@ -19,7 +20,7 @@ class VisibleFootnote extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Only visible to you',
|
context.translations.onlyVisibleToYouText,
|
||||||
style: chatThemeData.textTheme.footnote
|
style: chatThemeData.textTheme.footnote
|
||||||
.copyWith(color: chatThemeData.colorTheme.textLowEmphasis),
|
.copyWith(color: chatThemeData.colorTheme.textLowEmphasis),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export 'package:jiffy/jiffy.dart';
|
||||||
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
export 'src/attachment/attachment.dart';
|
export 'src/attachment/attachment.dart';
|
||||||
@@ -16,6 +17,8 @@ export 'src/gallery_footer.dart';
|
|||||||
export 'src/gallery_header.dart';
|
export 'src/gallery_header.dart';
|
||||||
export 'src/gradient_avatar.dart';
|
export 'src/gradient_avatar.dart';
|
||||||
export 'src/info_tile.dart';
|
export 'src/info_tile.dart';
|
||||||
|
export 'src/localization/stream_chat_localizations.dart';
|
||||||
|
export 'src/localization/translations.dart' show DefaultTranslations;
|
||||||
export 'src/mention_tile.dart';
|
export 'src/mention_tile.dart';
|
||||||
export 'src/message_action.dart';
|
export 'src/message_action.dart';
|
||||||
export 'src/message_input.dart';
|
export 'src/message_input.dart';
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
|||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
flutter: ">=1.17.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
cached_network_image: ^3.0.0
|
cached_network_image: ^3.0.0
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('Default translations should exist', () {
|
||||||
|
const translations = DefaultTranslations.instance;
|
||||||
|
expect(translations.launchUrlError, isNotNull);
|
||||||
|
expect(translations.loadingUsersError, isNotNull);
|
||||||
|
expect(translations.noUsersLabel, isNotNull);
|
||||||
|
expect(translations.retryLabel, isNotNull);
|
||||||
|
expect(translations.userLastOnlineText, isNotNull);
|
||||||
|
expect(translations.userOnlineText, isNotNull);
|
||||||
|
expect(translations.userOnlineText, isNotNull);
|
||||||
|
// no users
|
||||||
|
expect(translations.userTypingText([]), isNotNull);
|
||||||
|
// single user
|
||||||
|
expect(translations.userTypingText([User(id: 'test-id')]), isNotNull);
|
||||||
|
// multiple users
|
||||||
|
expect(
|
||||||
|
translations.userTypingText([
|
||||||
|
User(id: 'test-id-1'),
|
||||||
|
User(id: 'test-id-2'),
|
||||||
|
]),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(translations.threadReplyLabel, isNotNull);
|
||||||
|
expect(translations.onlyVisibleToYouText, isNotNull);
|
||||||
|
expect(translations.threadReplyCountText(3), isNotNull);
|
||||||
|
expect(
|
||||||
|
translations.attachmentsUploadProgressText(remaining: 3, total: 10),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
translations.pinnedByUserText(
|
||||||
|
pinnedBy: User(id: 'pinned-by-user-id'),
|
||||||
|
currentUser: OwnUser(id: 'current-user-id'),
|
||||||
|
),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(translations.emptyMessagesText, isNotNull);
|
||||||
|
expect(translations.genericErrorText, isNotNull);
|
||||||
|
expect(translations.loadingMessagesError, isNotNull);
|
||||||
|
expect(translations.resultCountText(3), isNotNull);
|
||||||
|
expect(translations.messageDeletedText, isNotNull);
|
||||||
|
expect(translations.messageDeletedLabel, isNotNull);
|
||||||
|
expect(translations.messageReactionsLabel, isNotNull);
|
||||||
|
expect(translations.emptyChatMessagesText, isNotNull);
|
||||||
|
expect(translations.threadSeparatorText(3), isNotNull);
|
||||||
|
expect(translations.connectedLabel, isNotNull);
|
||||||
|
expect(translations.disconnectedLabel, isNotNull);
|
||||||
|
expect(translations.reconnectingLabel, isNotNull);
|
||||||
|
expect(translations.alsoSendAsDirectMessageLabel, isNotNull);
|
||||||
|
expect(translations.addACommentOrSendLabel, isNotNull);
|
||||||
|
expect(translations.searchGifLabel, isNotNull);
|
||||||
|
expect(translations.writeAMessageLabel, isNotNull);
|
||||||
|
expect(translations.instantCommandsLabel, isNotNull);
|
||||||
|
expect(translations.fileTooLargeAfterCompressionError(33), isNotNull);
|
||||||
|
expect(translations.fileTooLargeError(33), isNotNull);
|
||||||
|
expect(translations.emojiMatchingQueryText('sahil'), isNotNull);
|
||||||
|
expect(translations.addAFileLabel, isNotNull);
|
||||||
|
expect(translations.photoFromCameraLabel, isNotNull);
|
||||||
|
expect(translations.uploadAFileLabel, isNotNull);
|
||||||
|
expect(translations.uploadAPhotoLabel, isNotNull);
|
||||||
|
expect(translations.uploadAVideoLabel, isNotNull);
|
||||||
|
expect(translations.videoFromCameraLabel, isNotNull);
|
||||||
|
expect(translations.okLabel, isNotNull);
|
||||||
|
expect(translations.somethingWentWrongError, isNotNull);
|
||||||
|
expect(translations.addMoreFilesLabel, isNotNull);
|
||||||
|
expect(translations.enablePhotoAndVideoAccessMessage, isNotNull);
|
||||||
|
expect(translations.allowGalleryAccessMessage, isNotNull);
|
||||||
|
expect(translations.flagMessageLabel, isNotNull);
|
||||||
|
expect(translations.flagMessageQuestion, isNotNull);
|
||||||
|
expect(translations.flagLabel, isNotNull);
|
||||||
|
expect(translations.cancelLabel, isNotNull);
|
||||||
|
expect(translations.flagMessageSuccessfulLabel, isNotNull);
|
||||||
|
expect(translations.flagMessageSuccessfulText, isNotNull);
|
||||||
|
expect(translations.deleteLabel, isNotNull);
|
||||||
|
expect(translations.deleteMessageLabel, isNotNull);
|
||||||
|
expect(translations.deleteMessageQuestion, isNotNull);
|
||||||
|
expect(translations.operationCouldNotBeCompletedText, isNotNull);
|
||||||
|
expect(translations.replyLabel, isNotNull);
|
||||||
|
// pinned
|
||||||
|
expect(translations.togglePinUnpinText(pinned: true), isNotNull);
|
||||||
|
// un-pinned
|
||||||
|
expect(translations.togglePinUnpinText(pinned: false), isNotNull);
|
||||||
|
// delete-failed
|
||||||
|
expect(
|
||||||
|
translations.toggleDeleteRetryDeleteMessageText(isDeleteFailed: true),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
// first-delete
|
||||||
|
expect(
|
||||||
|
translations.toggleDeleteRetryDeleteMessageText(isDeleteFailed: false),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(translations.copyMessageLabel, isNotNull);
|
||||||
|
expect(translations.editMessageLabel, isNotNull);
|
||||||
|
// resend-failed
|
||||||
|
expect(
|
||||||
|
translations.toggleResendOrResendEditedMessage(isUpdateFailed: true),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
// first resend
|
||||||
|
expect(
|
||||||
|
translations.toggleResendOrResendEditedMessage(isUpdateFailed: false),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(translations.photosLabel, isNotNull);
|
||||||
|
// today
|
||||||
|
expect(
|
||||||
|
translations.sentAtText(
|
||||||
|
date: DateTime.now(),
|
||||||
|
time: DateTime.now(),
|
||||||
|
),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
// yesterday
|
||||||
|
expect(
|
||||||
|
translations.sentAtText(
|
||||||
|
date: DateTime.now().subtract(const Duration(days: 1)),
|
||||||
|
time: DateTime.now(),
|
||||||
|
),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
// any other day
|
||||||
|
expect(
|
||||||
|
translations.sentAtText(
|
||||||
|
date: DateTime.now().subtract(const Duration(days: 3)),
|
||||||
|
time: DateTime.now(),
|
||||||
|
),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
expect(translations.todayLabel, isNotNull);
|
||||||
|
expect(translations.yesterdayLabel, isNotNull);
|
||||||
|
expect(translations.channelIsMutedText, isNotNull);
|
||||||
|
expect(translations.noTitleText, isNotNull);
|
||||||
|
expect(translations.letsStartChattingLabel, isNotNull);
|
||||||
|
expect(translations.sendingFirstMessageLabel, isNotNull);
|
||||||
|
expect(translations.startAChatLabel, isNotNull);
|
||||||
|
expect(translations.loadingChannelsError, isNotNull);
|
||||||
|
expect(translations.deleteConversationLabel, isNotNull);
|
||||||
|
expect(translations.deleteConversationQuestion, isNotNull);
|
||||||
|
expect(translations.streamChatLabel, isNotNull);
|
||||||
|
expect(translations.searchingForNetworkText, isNotNull);
|
||||||
|
expect(translations.offlineLabel, isNotNull);
|
||||||
|
expect(translations.tryAgainLabel, isNotNull);
|
||||||
|
// 1 member
|
||||||
|
expect(translations.membersCountText(1), isNotNull);
|
||||||
|
// 3 members
|
||||||
|
expect(translations.membersCountText(3), isNotNull);
|
||||||
|
// 1 member
|
||||||
|
expect(translations.watchersCountText(1), isNotNull);
|
||||||
|
// 3 members
|
||||||
|
expect(translations.watchersCountText(3), isNotNull);
|
||||||
|
expect(translations.viewInfoLabel, isNotNull);
|
||||||
|
expect(translations.leaveGroupLabel, isNotNull);
|
||||||
|
expect(translations.leaveLabel, isNotNull);
|
||||||
|
expect(translations.leaveConversationLabel, isNotNull);
|
||||||
|
expect(translations.leaveConversationQuestion, isNotNull);
|
||||||
|
expect(translations.showInChatLabel, isNotNull);
|
||||||
|
expect(translations.saveImageLabel, isNotNull);
|
||||||
|
expect(translations.saveVideoLabel, isNotNull);
|
||||||
|
expect(translations.uploadErrorLabel, isNotNull);
|
||||||
|
expect(translations.giphyLabel, isNotNull);
|
||||||
|
expect(translations.shuffleLabel, isNotNull);
|
||||||
|
expect(translations.sendLabel, isNotNull);
|
||||||
|
expect(translations.withText, isNotNull);
|
||||||
|
expect(translations.inText, isNotNull);
|
||||||
|
expect(translations.youText, isNotNull);
|
||||||
|
expect(translations.ofText, isNotNull);
|
||||||
|
expect(translations.fileText, isNotNull);
|
||||||
|
expect(translations.replyToMessageLabel, isNotNull);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -717,7 +717,7 @@ void main() {
|
|||||||
await tester.tap(find.text('Delete Message'));
|
await tester.tap(find.text('Delete Message'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.text('Delete message'), findsOneWidget);
|
expect(find.text('Delete Message'), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.text('DELETE'));
|
await tester.tap(find.text('DELETE'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
@@ -773,7 +773,7 @@ void main() {
|
|||||||
await tester.tap(find.text('Delete Message'));
|
await tester.tap(find.text('Delete Message'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.text('Delete message'), findsOneWidget);
|
expect(find.text('Delete Message'), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.text('DELETE'));
|
await tester.tap(find.text('DELETE'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Flutter.podspec
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/Flutter/flutter_export_environment.sh
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: d79295af24c3ed621c33713ecda14ad196fd9c31
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
project_type: package
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
* First release
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
SOURCE CODE LICENSE AGREEMENT
|
||||||
|
|
||||||
|
IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR
|
||||||
|
ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT.
|
||||||
|
|
||||||
|
THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE
|
||||||
|
BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE
|
||||||
|
LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN
|
||||||
|
INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN
|
||||||
|
EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE
|
||||||
|
OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN
|
||||||
|
AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO
|
||||||
|
THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND
|
||||||
|
CUSTOMER TO THIS AGREEMENT.
|
||||||
|
|
||||||
|
STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING
|
||||||
|
CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A
|
||||||
|
COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS
|
||||||
|
AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE
|
||||||
|
USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU
|
||||||
|
REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF
|
||||||
|
STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE
|
||||||
|
READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE
|
||||||
|
BOUND BY ALL THE TERMS OF THIS AGREEMENT.
|
||||||
|
|
||||||
|
IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT,
|
||||||
|
STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO
|
||||||
|
NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND
|
||||||
|
CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
1. SOFTWARE. The Stream.io software accompanying this Agreement, may include
|
||||||
|
Source Code, Executable Object Code, associated media, printed materials and
|
||||||
|
documentation (collectively, the “Software”). The Software also includes any
|
||||||
|
updates or upgrades to or new versions of the original Software, if and when
|
||||||
|
made available to you by Stream.io. “Source Code” means computer programming
|
||||||
|
code in human readable form that is not suitable for machine execution without
|
||||||
|
the intervening steps of interpretation or compilation. “Executable Object
|
||||||
|
Code" means the computer programming code in any other form than Source Code
|
||||||
|
that is not readily perceivable by humans and suitable for machine execution
|
||||||
|
without the intervening steps of interpretation or compilation. “Site” means a
|
||||||
|
Customer location controlled by Customer. “Authorized User” means any employee
|
||||||
|
or contractor of Customer working at the Site, who has signed a written
|
||||||
|
confidentiality agreement with Customer or is otherwise bound in writing by
|
||||||
|
confidentiality and use obligations at least as restrictive as those imposed
|
||||||
|
under this Agreement.
|
||||||
|
|
||||||
|
2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in
|
||||||
|
consideration for the representations, warranties, and covenants made by
|
||||||
|
Customer in this Agreement, Stream.io grants to Customer, during the term of
|
||||||
|
this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable
|
||||||
|
license to:
|
||||||
|
|
||||||
|
a. install and use Software Source Code on password protected computers at a Site,
|
||||||
|
restricted to Authorized Users;
|
||||||
|
|
||||||
|
b. create derivative works, improvements (whether or not patentable), extensions
|
||||||
|
and other modifications to the Software Source Code (“Modifications”) to build
|
||||||
|
unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s
|
||||||
|
application program interface (“API”);
|
||||||
|
|
||||||
|
c. compile the Software Source Code to create Executable Object Code versions of
|
||||||
|
the Software Source Code and Modifications to build such newsfeeds, activity
|
||||||
|
streams, and in-app messaging via the API;
|
||||||
|
|
||||||
|
d. install, execute and use such Executable Object Code versions solely for
|
||||||
|
Customer’s internal business use (including development of websites through
|
||||||
|
which data generated by Stream services will be streamed (“Apps”));
|
||||||
|
|
||||||
|
e. use and distribute such Executable Object Code as part of Customer’s Apps; and
|
||||||
|
|
||||||
|
f. make electronic copies of the Software and Modifications as required for backup
|
||||||
|
or archival purposes.
|
||||||
|
|
||||||
|
3. RESTRICTIONS. Customer is responsible for all activities that occur in
|
||||||
|
connection with the Software. Customer will not, and will not attempt to: (a)
|
||||||
|
sublicense or transfer the Software or any Source Code related to the Software
|
||||||
|
or any of Customer’s rights under this Agreement, except as otherwise provided
|
||||||
|
in this Agreement, (b) use the Software Source Code for the benefit of a third
|
||||||
|
party or to operate a service; (c) allow any third party to access or use the
|
||||||
|
Software Source Code; (d) sublicense or distribute the Software Source Code or
|
||||||
|
any Modifications in Source Code or other derivative works based on any part of
|
||||||
|
the Software Source Code; (e) use the Software in any manner that competes with
|
||||||
|
Stream.io or its business; or (e) otherwise use the Software in any manner that
|
||||||
|
exceeds the scope of use permitted in this Agreement. Customer shall use the
|
||||||
|
Software in compliance with any accompanying documentation any laws applicable
|
||||||
|
to Customer.
|
||||||
|
|
||||||
|
4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or
|
||||||
|
software components that are open source in conjunction with the Software
|
||||||
|
Source Code or any Modifications in Source Code or in any way that could
|
||||||
|
subject the Software to any open source licenses.
|
||||||
|
|
||||||
|
5. CONTRACTORS. Under the rights granted to Customer under this Agreement,
|
||||||
|
Customer may permit its employees, contractors, and agencies of Customer to
|
||||||
|
become Authorized Users to exercise the rights to the Software granted to
|
||||||
|
Customer in accordance with this Agreement solely on behalf of Customer to
|
||||||
|
provide services to Customer; provided that Customer shall be liable for the
|
||||||
|
acts and omissions of all Authorized Users to the extent any of such acts or
|
||||||
|
omissions, if performed by Customer, would constitute a breach of, or otherwise
|
||||||
|
give rise to liability to Customer under, this Agreement. Customer shall not
|
||||||
|
and shall not permit any Authorized User to use the Software except as
|
||||||
|
expressly permitted in this Agreement.
|
||||||
|
|
||||||
|
6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way
|
||||||
|
to engage in the development of products or services which could be reasonably
|
||||||
|
construed to provide a complete or partial functional or commercial alternative
|
||||||
|
to Stream.io’s products or services (a “Competitive Product”). Customer shall
|
||||||
|
ensure that there is no direct or indirect use of, or sharing of, Software
|
||||||
|
source code, or other information based upon or derived from the Software to
|
||||||
|
develop such products or services. Without derogating from the generality of
|
||||||
|
the foregoing, development of Competitive Products shall include having direct
|
||||||
|
or indirect access to, supervising, consulting or assisting in the development
|
||||||
|
of, or producing any specifications, documentation, object code or source code
|
||||||
|
for, all or part of a Competitive Product.
|
||||||
|
|
||||||
|
7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement,
|
||||||
|
Modifications may only be created and used by Customer as permitted by this
|
||||||
|
Agreement and Modification Source Code may not be distributed to third parties.
|
||||||
|
Customer will not assert against Stream.io, its affiliates, or their customers,
|
||||||
|
direct or indirect, agents and contractors, in any way, any patent rights that
|
||||||
|
Customer may obtain relating to any Modifications for Stream.io, its
|
||||||
|
affiliates’, or their customers’, direct or indirect, agents’ and contractors’
|
||||||
|
manufacture, use, import, offer for sale or sale of any Stream.io products or
|
||||||
|
services.
|
||||||
|
|
||||||
|
8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant
|
||||||
|
to Stream.io standard download procedures. The Software is deemed accepted upon
|
||||||
|
delivery.
|
||||||
|
|
||||||
|
9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to
|
||||||
|
provide any support or consultation concerning the Software.
|
||||||
|
|
||||||
|
10. TERM AND TERMINATION. The term of this Agreement begins when the Software is
|
||||||
|
downloaded or accessed and shall continue until terminated. Either party may
|
||||||
|
terminate this Agreement upon written notice. This Agreement shall
|
||||||
|
automatically terminate if Customer is or becomes a competitor of Stream.io or
|
||||||
|
makes or sells any Competitive Products. Upon termination of this Agreement for
|
||||||
|
any reason, (a) all rights granted to Customer in this Agreement immediately
|
||||||
|
cease to exist, (b) Customer must promptly discontinue all use of the Software
|
||||||
|
and return to Stream.io or destroy all copies of the Software in Customer’s
|
||||||
|
possession or control. Any continued use of the Software by Customer or attempt
|
||||||
|
by Customer to exercise any rights under this Agreement after this Agreement
|
||||||
|
has terminated shall be considered copyright infringement and subject Customer
|
||||||
|
to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9
|
||||||
|
shall survive expiration or termination of this Agreement for any reason.
|
||||||
|
|
||||||
|
11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual
|
||||||
|
property rights and proprietary rights relating thereto or embodied therein,
|
||||||
|
are the exclusive property of Stream.io and its suppliers. Stream.io and its
|
||||||
|
suppliers reserve all rights in and to the Software not expressly granted to
|
||||||
|
Customer in this Agreement, and no other licenses or rights are granted by
|
||||||
|
implication, estoppel or otherwise.
|
||||||
|
|
||||||
|
12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S
|
||||||
|
OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND
|
||||||
|
WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY
|
||||||
|
KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT
|
||||||
|
LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS,
|
||||||
|
QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS
|
||||||
|
ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED
|
||||||
|
THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS
|
||||||
|
SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO
|
||||||
|
MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND
|
||||||
|
DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW.
|
||||||
|
CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE
|
||||||
|
EXPRESS WARRANTIES IN THIS AGREEMENT.
|
||||||
|
|
||||||
|
13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S
|
||||||
|
TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR
|
||||||
|
THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE,
|
||||||
|
SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT,
|
||||||
|
CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND
|
||||||
|
WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING
|
||||||
|
TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON
|
||||||
|
ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO
|
||||||
|
THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY.
|
||||||
|
|
||||||
|
14. General. Customer may not assign or transfer this Agreement, by operation of
|
||||||
|
law or otherwise, or any of its rights under this Agreement (including the
|
||||||
|
license rights granted to Customer) to any third party without Stream.io’s
|
||||||
|
prior written consent, which consent will not be unreasonably withheld or
|
||||||
|
delayed. Stream.io may assign this Agreement, without consent, including, but
|
||||||
|
limited to, affiliate or any successor to all or substantially all its business
|
||||||
|
or assets to which this Agreement relates, whether by merger, sale of assets,
|
||||||
|
sale of stock, reorganization or otherwise. Any attempted assignment or
|
||||||
|
transfer in violation of the foregoing will be null and void. Stream.io shall
|
||||||
|
not be liable hereunder by reason of any failure or delay in the performance of
|
||||||
|
its obligations hereunder for any cause which is beyond the reasonable control.
|
||||||
|
All notices, consents, and approvals under this Agreement must be delivered in
|
||||||
|
writing by courier, by electronic mail, or by certified or registered mail,
|
||||||
|
(postage prepaid and return receipt requested) to the other party at the
|
||||||
|
address set forth in the customer agreement between Stream.io and Customer and
|
||||||
|
will be effective upon receipt or when delivery is refused. This Agreement will
|
||||||
|
be governed by and interpreted in accordance with the laws of the State of
|
||||||
|
Colorado, without reference to its choice of laws rules. The United Nations
|
||||||
|
Convention on Contracts for the International Sale of Goods does not apply to
|
||||||
|
this Agreement. Any action or proceeding arising from or relating to this
|
||||||
|
Agreement shall be brought in a federal or state court in Denver, Colorado, and
|
||||||
|
each party irrevocably submits to the jurisdiction and venue of any such court
|
||||||
|
in any such action or proceeding. All waivers must be in writing. Any waiver or
|
||||||
|
failure to enforce any provision of this Agreement on one occasion will not be
|
||||||
|
deemed a waiver of any other provision or of such provision on any other
|
||||||
|
occasion. If any provision of this Agreement is unenforceable, such provision
|
||||||
|
will be changed and interpreted to accomplish the objectives of such provision
|
||||||
|
to the greatest extent possible under applicable law and the remaining
|
||||||
|
provisions will continue in full force and effect. Customer shall not violate
|
||||||
|
any applicable law, rule or regulation, including those regarding the export of
|
||||||
|
technical data. The headings of Sections of this Agreement are for convenience
|
||||||
|
and are not to be used in interpreting this Agreement. As used in this
|
||||||
|
Agreement, the word “including” means “including but not limited to.” This
|
||||||
|
Agreement (including all exhibits and attachments) constitutes the entire
|
||||||
|
agreement between the parties regarding the subject hereof and supersedes all
|
||||||
|
prior or contemporaneous agreements, understandings and communication, whether
|
||||||
|
written or oral. This Agreement may be amended only by a written document
|
||||||
|
signed by both parties. The terms of any purchase order or similar document
|
||||||
|
submitted by Customer to Stream.io will have no effect.
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Official Localizations for [Stream Chat Flutter](https://getstream.io/chat/sdk/flutter/) library.
|
||||||
|
|
||||||
|
> The Official localizations for Stream Chat Flutter, a service for
|
||||||
|
> building chat applications.
|
||||||
|
|
||||||
|
[](https://pub.dartlang.org/packages/stream_chat_localizations)
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
**Quick Links**
|
||||||
|
|
||||||
|
- [Register](https://getstream.io/chat/trial/) to get an API key for Stream Chat
|
||||||
|
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
|
||||||
|
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
|
||||||
|
|
||||||
|
This package provides localized strings for the stream chat widgets for many languages.
|
||||||
|
|
||||||
|
### Changelog
|
||||||
|
|
||||||
|
Check out the [changelog on pub.dev](https://pub.dev/packages/stream_chat_localizations/changelog) to see the latest changes in the package.
|
||||||
|
|
||||||
|
## Supported languages
|
||||||
|
|
||||||
|
At the moment we support the following languages:
|
||||||
|
- [English](https://pub.dev/documentation/stream_chat_localizations/latest/stream_chat_localizations/StreamChatLocalizationsEn-class.html)
|
||||||
|
- [Hindi](https://pub.dev/documentation/stream_chat_localizations/latest/stream_chat_localizations/StreamChatLocalizationsHi-class.html)
|
||||||
|
- [Italian](https://pub.dev/documentation/stream_chat_localizations/latest/stream_chat_localizations/StreamChatLocalizationsIt-class.html)
|
||||||
|
- [French](https://pub.dev/documentation/stream_chat_localizations/latest/stream_chat_localizations/StreamChatLocalizationsFr-class.html)
|
||||||
|
|
||||||
|
More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages.
|
||||||
|
|
||||||
|
## Add dependency
|
||||||
|
|
||||||
|
Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_chat_localizations)
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
stream_chat_localizations: ^latest_version
|
||||||
|
```
|
||||||
|
|
||||||
|
You should then run `flutter packages get`
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat_localizations/stream_chat_localizations.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
runApp(MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
// Add all the supported locales
|
||||||
|
supportedLocales: const [
|
||||||
|
Locale('en'),
|
||||||
|
Locale('hi'),
|
||||||
|
Locale('fr'),
|
||||||
|
Locale('it'),
|
||||||
|
],
|
||||||
|
// Add GlobalStreamChatLocalizations.delegates
|
||||||
|
localizationsDelegates: GlobalStreamChatLocalizations.delegates,
|
||||||
|
builder: (context, widget) => StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: widget,
|
||||||
|
),
|
||||||
|
home: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: const ChannelPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding a new language
|
||||||
|
|
||||||
|
To add a new language, you need to create a new class extending `GlobalStreamChatLocalizations` and create a delegate for it adding it to the `delegates` array.
|
||||||
|
|
||||||
|
Checkout [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/add_new_lang.dart) to see how to add a new language.
|
||||||
|
|
||||||
|
### Override exisiting languages
|
||||||
|
|
||||||
|
To override an existing language, you need to create a new class extending that particular language class and create a delegate for it adding it to the `delegates` array.
|
||||||
|
|
||||||
|
Checkout [this example](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/example/lib/override_lang.dart) to see how to override an existing language.
|
||||||
|
|
||||||
|
### ⚠️ Note on **iOS**
|
||||||
|
|
||||||
|
For translation to work on **iOS** you need to add supported locales to
|
||||||
|
`ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<key>CFBundleLocalizations</key>
|
||||||
|
<array>
|
||||||
|
<string>en</string>
|
||||||
|
<string>nb</string>
|
||||||
|
<string>fr</string>
|
||||||
|
<string>it</string>
|
||||||
|
</array>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome code changes that improve this library or fix a problem,
|
||||||
|
please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github.
|
||||||
|
We are pleased to merge your code into the official repository.
|
||||||
|
Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first.
|
||||||
|
See our license file for more details.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Web related
|
||||||
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: 78910062997c3a836feee883712c241a5fd22983
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
project_type: app
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Stream Chat Persistence Example
|
||||||
|
Please see `lib/` for example code.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
|
key.properties
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
def localProperties = new Properties()
|
||||||
|
def localPropertiesFile = rootProject.file('local.properties')
|
||||||
|
if (localPropertiesFile.exists()) {
|
||||||
|
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||||
|
localProperties.load(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||||
|
if (flutterRoot == null) {
|
||||||
|
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||||
|
if (flutterVersionCode == null) {
|
||||||
|
flutterVersionCode = '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||||
|
if (flutterVersionName == null) {
|
||||||
|
flutterVersionName = '1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
checkReleaseBuilds false
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
|
applicationId "com.example.example"
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 30
|
||||||
|
versionCode flutterVersionCode.toInteger()
|
||||||
|
versionName flutterVersionName
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
// TODO: Add your own signing config for the release build.
|
||||||
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flutter {
|
||||||
|
source '../..'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.example">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.example">
|
||||||
|
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||||
|
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||||
|
In most cases you can leave this as-is, but you if you want to provide
|
||||||
|
additional functionality it is fine to subclass or reimplement
|
||||||
|
FlutterApplication and put your custom class here. -->
|
||||||
|
<application
|
||||||
|
android:name="io.flutter.app.FlutterApplication"
|
||||||
|
android:label="example"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
the Android process has started. This theme is visible to the user
|
||||||
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
to determine the Window background behind the Flutter UI. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
|
android:resource="@style/NormalTheme"
|
||||||
|
/>
|
||||||
|
<!-- Displays an Android View that continues showing the launch screen
|
||||||
|
Drawable until Flutter paints its first frame, then this splash
|
||||||
|
screen fades out. A splash screen is useful to avoid any visual
|
||||||
|
gap between the end of Android's launch screen and the painting of
|
||||||
|
Flutter's first frame. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||||
|
android:resource="@drawable/launch_background"
|
||||||
|
/>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- Don't delete the meta-data below.
|
||||||
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutterEmbedding"
|
||||||
|
android:value="2" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.example.example
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@android:color/white" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 442 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.example">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.5.20'
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.buildDir = '../build'
|
||||||
|
subprojects {
|
||||||
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
}
|
||||||
|
subprojects {
|
||||||
|
project.evaluationDependsOn(':app')
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
android.enableR8=true
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#Fri Jun 23 08:50:38 CEST 2017
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
include ':app'
|
||||||
|
|
||||||
|
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||||
|
def properties = new Properties()
|
||||||
|
|
||||||
|
assert localPropertiesFile.exists()
|
||||||
|
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||||
|
|
||||||
|
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||||
|
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
0E9B23A7BA08E142FA5000CF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D76F8024ABE1070895D659BA /* Pods_Runner.framework */; };
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
3F6A054EEDAF06BCF649C130 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6FE1ECA061EBB001F6BCE8B7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
D76F8024ABE1070895D659BA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
EC2A45E9198C1011BED23834 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
0E9B23A7BA08E142FA5000CF /* Pods_Runner.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
04AAB960E493BD92262BBF82 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D76F8024ABE1070895D659BA /* Pods_Runner.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
8559384DCD98ED6067CEF8CB /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3F6A054EEDAF06BCF649C130 /* Pods-Runner.debug.xcconfig */,
|
||||||
|
EC2A45E9198C1011BED23834 /* Pods-Runner.release.xcconfig */,
|
||||||
|
6FE1ECA061EBB001F6BCE8B7 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Flutter;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146E51CF9000F007C117D = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
8559384DCD98ED6067CEF8CB /* Pods */,
|
||||||
|
04AAB960E493BD92262BBF82 /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
);
|
||||||
|
path = Runner;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
|
buildPhases = (
|
||||||
|
C1EE41B94EADE099F7AF3A1C /* [CP] Check Pods Manifest.lock */,
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
BD38DACC9A0AD429D9ED9939 /* [CP] Embed Pods Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Runner;
|
||||||
|
productName = Runner;
|
||||||
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 1020;
|
||||||
|
ORGANIZATIONNAME = "";
|
||||||
|
TargetAttributes = {
|
||||||
|
97C146ED1CF9000F007C117D = {
|
||||||
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
BD38DACC9A0AD429D9ED9939 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
C1EE41B94EADE099F7AF3A1C /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C146FB1CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C147001CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147041CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
97C147061CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147071CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147031CF9000F007C117D /* Debug */,
|
||||||
|
97C147041CF9000F007C117D /* Release */,
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147061CF9000F007C117D /* Debug */,
|
||||||
|
97C147071CF9000F007C117D /* Release */,
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1020"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Profile"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import UIKit
|
||||||
|
import Flutter
|
||||||
|
|
||||||
|
@UIApplicationMain
|
||||||
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
|
override func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |