Created
November 2, 2019 12:32
-
-
Save danielsmykowski1/cafc047b7f51f720c0ba06ec2f88a628 to your computer and use it in GitHub Desktop.
AngularDart message input component for chatting PWA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:host { | |
background-color: #eae0da; | |
width: 100%; | |
display: -ms-flexbox; | |
display: -webkit-flex; | |
display: flex; | |
-ms-flex-direction: row; | |
-webkit-flex-direction: row; | |
flex-direction: row; | |
-ms-flex-align: center; | |
-webkit-align-items: center; | |
align-items: center; | |
} | |
input[type="file"] { | |
display: none; | |
} | |
.mic-icon { | |
padding-left: 8px; | |
padding-right: 8px; | |
opacity: 0; | |
transition: opacity 250ms ease-in-out; | |
} | |
.mic-icon.show { | |
opacity: 1; | |
} | |
material-fab.green { | |
background-color: #0f9d58; | |
color: #fff; | |
} | |
material-icon.attach_file { | |
transform: rotate(-45deg); | |
} | |
.input-group { | |
background-color: #fff; | |
border-radius: 20px; | |
margin: 5px; | |
} | |
.input-group material-fab { | |
margin: 0; | |
} | |
/* message input box style */ | |
material-input.input-message { | |
width: 50px; | |
} | |
material-input.input-message ::ng-deep .bottom-section { | |
display: none; | |
} | |
material-input.input-message ::ng-deep .baseline .underline { | |
display: none; | |
} | |
material-input.input-message ::ng-deep .baseline .top-section { | |
margin-bottom: 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:angular/angular.dart'; | |
import 'dart:html'; | |
import 'dart:async'; | |
import 'package:angular_components/angular_components.dart'; | |
@Component( | |
selector: 'message-input', | |
templateUrl: 'message_input_component.html', | |
styleUrls: ['message_input_component.css'], | |
directives: [ | |
coreDirectives, | |
materialInputDirectives, | |
MaterialInputComponent, | |
MaterialButtonComponent, | |
MaterialIconComponent, | |
MaterialFabComponent, | |
MaterialMultilineInputComponent, | |
], | |
providers: [materialProviders] | |
) | |
class MessageInputComponent { | |
final _messageChange = StreamController<String>(); | |
@Output() | |
Stream<String> get messageChange => _messageChange.stream; | |
String _message = ""; | |
String get message => _message; | |
@Input() | |
set message(String val) { | |
_message = val; | |
_messageChange.add(val); | |
} | |
bool _inputDisabled; | |
get inputDisabled => _inputDisabled; | |
@Input() | |
set inputDisabled(bool val) => _inputDisabled = val; | |
bool _showSendButton = false; | |
get showSendButton => _showSendButton; | |
@Input() | |
set showSendButton(bool val) => _showSendButton = val; | |
bool _micAllowed = false; | |
bool get micAllowed => _micAllowed; | |
@Input() | |
set micAllowed(bool val) => _micAllowed = val; | |
bool _isRecording = false; | |
bool get isRecording => _isRecording; | |
@Input() | |
set isRecording(bool val) => _isRecording = val; | |
bool _showingMic = false; | |
bool get showingMic => _showingMic; | |
@Input() | |
set showingMic(bool val) => _showingMic = val; | |
bool _cameraAsNormalButton = false; | |
bool get cameraAsNormalButton => _cameraAsNormalButton; | |
@Input() | |
set cameraAsNormalButton(bool val) => _cameraAsNormalButton = val; | |
final _messageTrigger = StreamController<String>.broadcast(sync: true); | |
@Output() | |
get messageTrigger => _messageTrigger.stream; | |
final _contentChangedController = StreamController<Event>.broadcast(sync: true); | |
@Output() | |
get contentChanged => _contentChangedController.stream; | |
final _imageChangedController = StreamController<FileList>.broadcast(sync: true); | |
@Output() | |
get imageChanged => _imageChangedController.stream; | |
final _attachedController = StreamController<FileList>.broadcast(sync: true); | |
@Output() | |
get attached => _attachedController.stream; | |
final _micClickedController = StreamController<Event>.broadcast(sync: true); | |
@Output() | |
get micClicked => _micClickedController.stream; | |
final _cancelClickedController = StreamController<Event>.broadcast(sync: true); | |
@Output() | |
get cancelClicked => _cancelClickedController.stream; | |
final _cameraClickedController = StreamController<Event>.broadcast(sync: true); | |
@Output() | |
get cameraClicked => _cameraClickedController.stream; | |
void handleEnter(KeyboardEvent event) { | |
event.preventDefault(); | |
sendTextMessage(); | |
} | |
void sendTextMessage() { | |
String messageText = message.trim(); | |
if (messageText.isNotEmpty || showSendButton) { | |
_messageTrigger.add(messageText); | |
} | |
} | |
void handleKeyPress() { | |
_contentChangedController.add(Event('contentChanged')); | |
} | |
void handleImageChange(FileList list) { | |
_imageChangedController.add(list); | |
} | |
void handleAttachment(FileList list) { | |
_attachedController.add(list); | |
} | |
void handleMicClicked() { | |
_micClickedController.add(Event('mic button clicked')); | |
} | |
void handleCancelClicked() { | |
_cancelClickedController.add(Event('cancel clicked')); | |
} | |
void handleCameraClicked() { | |
_cameraClickedController.add(Event('camera clicked')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="input-group layout horizontal center flex"> | |
<material-fab mini [disabled]="inputDisabled" *ngIf="!isRecording"> | |
<material-icon icon="sentiment_satisfied_alt"></material-icon> | |
</material-fab> | |
<material-icon | |
icon="mic" | |
class="mic-icon" | |
*ngIf="isRecording" | |
[ngClass]="showingMic ? 'show' : ''" | |
></material-icon> | |
<material-input | |
class="flex input-message" | |
label="Type a message" | |
multiline | |
[(ngModel)]="message" | |
(keydown.enter)="handleEnter($event)" | |
(inputKeyPress)="handleKeyPress" | |
(change)="handleKeyPress" | |
[disabled]="inputDisabled || isRecording" | |
></material-input> | |
<material-fab | |
mini | |
(trigger)="attachment.click()" | |
[disabled]="inputDisabled" | |
*ngIf="!isRecording" | |
> | |
<material-icon icon="attach_file" class="attach_file"></material-icon> | |
</material-fab> | |
<material-fab mini | |
(trigger)="cameraAsNormalButton ? handleCameraClicked() : mediaCapture.click()" | |
[disabled]="inputDisabled" | |
*ngIf="!isRecording" | |
> | |
<material-icon icon="camera_alt"></material-icon> | |
</material-fab> | |
<material-button mini | |
(trigger)="handleCancelClicked" | |
*ngIf="isRecording" | |
> | |
Cancel | |
</material-button> | |
</div> | |
<input | |
#attachment | |
type="file" | |
accept="image/*" | |
(change)="handleAttachment(attachment.files)" | |
> | |
<input | |
#mediaCapture | |
type="file" | |
(change)="handleImageChange(mediaCapture.files)" | |
> | |
<material-fab | |
mini | |
class="green" | |
*ngIf="message == '' && !showSendButton" | |
[disabled]="inputDisabled" | |
(trigger)="handleMicClicked" | |
> | |
<material-icon icon="mic"></material-icon> | |
</material-fab> | |
<material-fab | |
mini | |
class="green" | |
*ngIf="message != '' || showSendButton" | |
(trigger)="sendTextMessage()" | |
[disabled]="inputDisabled" | |
> | |
<material-icon icon="send"></material-icon> | |
</material-fab> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment