How to break the loop for a stream in dart? - dart

I known the listen can be abort by StreamSubscription. But for some reason, I can not call listen for the File.openRead(). How can I abort the read operation stream?
import 'dart:io';
import 'dart:async';
class Reader {
Stream<int> progess(File file) async* {
var sum = 0;
var fs = file.openRead();
await for (var d in fs) {
// consume d
sum += d.length;
yield sum;
}
}
void cancel() {
// How to abort the above loop without using StreamSubscription returned by listen().
}
}
void main() async {
var reader = Reader();
var file = File.new("a.txt");
reader.progess(file).listen((p) => print("$p"));
// How to cancel it without
Future.delayed(Duration(seconds: 1), () { reader.cancel()});
}

You cannot cancel the stream subscription without calling cancel on the stream subscription.
You might be able to interrupt the stream producer in some other way, using a "side channel" to ask it to stop producing values. That's not a stream cancel, more like a premature stream close.
Example:
class Reader {
bool _cancelled = false;
Stream<int> progess(File file) async* {
var sum = 0;
var fs = file.openRead();
await for (var d in fs) {
// consume d
sum += d.length;
if (_cancelled) return; // <---
yield sum;
}
}
void cancel() {
_cancelled = true;
}
}
Another option is to create a general stream wrapper which can interrupt the stream. Maybe something like
import"dart:async";
class CancelableStream<T> extends Stream<T> {
final Stream<T> _source;
final Set<_CancelableStreamSubscription<T>> _subscriptions = {};
CancelableStream(Stream<T> source) : _source = source;
#override
StreamSubscription<T> listen(
onData, {onError, onDone, cancelOnError}) {
var sub = _source.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
var canSub = _CancelableStreamSubscription<T>(sub, this, cancelOnError ?? false);
_subscriptions.add(canSub);
return canSub;
}
void cancelAll() {
while (_subscriptions.isNotEmpty) {
_subscriptions.first.cancel();
}
}
}
class _CancelableStreamSubscription<T> implements StreamSubscription<T> {
final bool _cancelOnError;
final StreamSubscription<T> _source;
final CancelableStream<T> _owner;
_CancelableStreamSubscription(
this._source, this._owner, this._cancelOnError);
#override
Future<void> cancel() {
_owner._subscriptions.remove(this);
return _source.cancel();
}
#override
void onData(f) => _source.onData(f);
#override
void onError(f) {
if (!_cancelOnError) {
_source.onError(f);
} else {
_source.onError((Object e, StackTrace s) {
_owner._subscriptions.remove(this);
if (f is void Function(Object, StackTrace)) {
f(e, s);
} else {
f?.call(e);
}
});
}
}
#override
bool get isPaused => _source.isPaused;
#override
void onDone(f) => _source.onDone(() {
_owner._subscriptions.remove(this);
f?.call();
});
#override
void pause([resumeFuture]) => _source.pause(resumeFuture);
#override
void resume() => _source.resume;
#override
Future<E> asFuture<E>([E? value]) => _source.asFuture(value);
}
You can then use it like:
void main() async {
Stream<int> foo() async* {
yield 1;
yield 2;
yield 3;
yield 4;
}
var s = CancelableStream<int>(foo());
await for (var x in s) {
print(x);
if (x == 2) s.cancelAll();
}
}

Related

How to convert audio to text without stopping

I have an application that converts audio to text. I wanted that when the recording stops the text and starts again, it continues on the same previous recording and does not start again.
This is my code:
I've searched many threads and couldn't find a solution
My application is based on written voice recording so that the user speaks into the phone’s microphone and the voice is converted into text, but when it stops and starts again in recording, the converted text is recorded from the beginning, so I wanted it to continue on the previous text
getWindow ().addFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
returnedText = (EditText) findViewById (R.id.textView1);
progressBar = (ProgressBar) findViewById (R.id.progressBar1);
toggleButton = (ToggleButton) findViewById (R.id.toggleButton1);
Copy = (Button) findViewById (R.id.copy);
Share = (Button) findViewById (R.id.share);
progressBar.setVisibility (View.INVISIBLE);
speech = SpeechRecognizer.createSpeechRecognizer (this);
Log.i (LOG_TAG,"isRecognitionAvailable: " + SpeechRecognizer.isRecognitionAvailable (this));
speech.setRecognitionListener (this);
recognizerIntent = new Intent (RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra (RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE,
"ar");
recognizerIntent.putExtra (RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
// تغير اللغة
recognizerIntent.putExtra (RecognizerIntent.EXTRA_LANGUAGE,"ar");
recognizerIntent.putExtra (RecognizerIntent.EXTRA_MAX_RESULTS,1);
toggleButton.setOnCheckedChangeListener (new CompoundButton.OnCheckedChangeListener () {
#Override
public void onCheckedChanged ( CompoundButton buttonView,
boolean isChecked ) {
if (isChecked) {
progressBar.setVisibility (View.VISIBLE);
progressBar.setIndeterminate (true);
ActivityCompat.requestPermissions
(Arabick.this,
new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_PERMISSION);
} else {
progressBar.setIndeterminate (false);
progressBar.setVisibility (View.INVISIBLE);
speech.stopListening ();
}
}
});
}
#Override
public void onRequestPermissionsResult ( int requestCode,#NonNull String[] permissions,#NonNull int[] grantResults ) {
super.onRequestPermissionsResult (requestCode,permissions,grantResults);
switch (requestCode) {
case REQUEST_RECORD_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
speech.startListening (recognizerIntent);
} else {
Toast.makeText (Arabick.this,"Permission Denied!",Toast
.LENGTH_SHORT).show ();
}
}
// recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ar-SA");
Copy.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick ( View v ) {
// ������ ���� ���� ������� ���� txtText
copy_content = returnedText.getText ().toString ();
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
clipboard.setText (copy_content);
// ��� ����� ����� ���� ���� ������ ����
Toast.makeText (getApplicationContext (),"تم النسخ ",Toast.LENGTH_SHORT).show ();
}
});
// ����� �� ������� ����
Share.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick ( View v ) {
copy_content = returnedText.getText ().toString ();
Intent sendIntent = new Intent ();
sendIntent.setAction (Intent.ACTION_SEND);
sendIntent.putExtra (Intent.EXTRA_TEXT,copy_content);
sendIntent.setType ("text/plain");
startActivity (Intent.createChooser (sendIntent,"Select the application:"));
}
});
}
#Override
public void onResume () {
super.onResume ();
}
#Override
protected void onPause () {
super.onPause ();
}
#Override
protected void onStop () {
super.onStop ();
if (speech != null) {
speech.destroy ();
Log.i (LOG_TAG,"destroy");
}
}
#Override
public void onBeginningOfSpeech () {
Log.i (LOG_TAG,"onBeginningOfSpeech");
progressBar.setIndeterminate (false);
progressBar.setMax (10);
}
#Override
public void onBufferReceived ( byte[] buffer ) {
Log.i (LOG_TAG,"onBufferReceived: " + buffer);
}
#Override
public void onEndOfSpeech () {
Log.i (LOG_TAG,"onEndOfSpeech");
progressBar.setIndeterminate (true);
toggleButton.setChecked (false);
}
#Override
public void onError ( int errorCode ) {
String errorMessage = getErrorText (errorCode);
Log.d (LOG_TAG,"FAILED " + errorMessage);
returnedText.setText (errorMessage);
toggleButton.setChecked (false);
}
#Override
public void onEvent ( int arg0,Bundle arg1 ) {
Log.i (LOG_TAG,"onEvent");
}
#Override
public void onPartialResults ( Bundle arg0 ) {
Log.i (LOG_TAG,"onPartialResults");
}
#Override
public void onReadyForSpeech ( Bundle arg0 ) {
Log.i (LOG_TAG,"onReadyForSpeech");
}
#Override
public void onResults ( Bundle results ) {
Log.i (LOG_TAG,"onResults");
ArrayList < String > matches = results
.getStringArrayList (SpeechRecognizer.RESULTS_RECOGNITION);
String text = "";
for (String result : matches)
text += result + "\n";
returnedText.setText (text);
}
#Override
public void onRmsChanged ( float rmsdB ) {
Log.i (LOG_TAG,"onRmsChanged: " + rmsdB);
progressBar.setProgress ((int) rmsdB);
}
}

Why I can't cancel `StreamGroup` subscription immediately

I want to listen to events from multiple Stream sources until I get a stop event. After that, I would like to unsubscribe. I expect that takeWhile cancels the subscription, but it doesn't seem to work until it's finished awaiting Future.
Here is my code below:
void main() async {
await StreamGroup.merge([_test2(), _test1()])
.takeWhile((element) => element != -1)
.forEach((element) {
print('Element=$element');
});
print('Finished!');
}
Stream<int> _test1() async* {
for (var i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
yield -1;
}
Stream<int> _test2() async* {
await longUserAction();
for (var i = 10; i < 20; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
yield -1;
}
Future<void> longUserAction() => Future.delayed(Duration(seconds: 20));
What I except:
Element=0
Element=1
Element=2
Element=3
Element=4
Finished!
What I got:
Element=0
Element=1
Element=2
Element=3
Element=4
*long pause*
Finished!
Here is the solution for my case:
class _SubscriptionData<T> {
final Stream<T> source;
final StreamSubscription<T> subscription;
bool isClosed = false;
_SubscriptionData(this.source, this.subscription);
void cancelSubscription() {
if (!isClosed) {
isClosed = true;
subscription.cancel();
}
}
}
class _MergeStreamController<T> {
final StreamController<T> _controller = StreamController<T>();
int workingStreamsCount = 0;
_MergeStreamController(List<Stream<T>> sources, bool Function(T) predicate) {
workingStreamsCount = sources.length;
final List<_SubscriptionData<T>> subscriptions = sources
.map((source) => _SubscriptionData(source, source.listen(null)))
.toList(growable: false);
void cancelAll() {
subscriptions.forEach((sub) {
sub.cancelSubscription();
});
}
subscriptions.forEach((subsData) {
subsData.subscription.onData((data) {
if (!predicate(data)) {
workingStreamsCount = 0;
_controller.close();
cancelAll();
} else if (!_controller.isClosed) _controller.add(data);
});
subsData.subscription.onDone(() {
if (--workingStreamsCount <= 0) _controller.close();
subsData.cancelSubscription();
});
});
}
}
/// Merges [sources] streams into a single stream channel
/// Stream closes when the first [source] stream emits event which is not satisfying predicate
/// or all streams done its work.
Stream<T> mergeStreamsWhile<T>(
List<Stream<T>> sources, bool Function(T) takeWhile) =>
_MergeStreamController(sources, takeWhile)._controller.stream;
void main() async {
await mergeStreamsWhile(
[_test2(), _test1(), _test3()], (element) => element != -1)
.forEach((element) {
print('Element=$element');
});
print('Finished!');
}
Stream<int> _test1() async* {
for (var i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
yield -1;
}
Stream<int> _test2() async* {
await longUserAction();
for (var i = 10; i < 20; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
yield -1;
}
Stream<int> _test3() async* {
return; // Simulate an empty stream
}
Future<void> longUserAction() => Future.delayed(Duration(seconds: 20));
Output:
Element=0
Element=1
Element=2
Element=3
Element=4
Finished!

Dart append to file when i use transform in read text from file

in this simple code i can show all fetched ids when finished reading file and get id from text file, but i want to append this fetched id inside JsonObjectTransformer class, not finished reading file
Future<void> main() async {
final ids = await File('sample.json')
.openRead()
.transform(const Utf8Decoder())
.transform<dynamic>(JsonObjectTransformer())
.map((dynamic json) => json['id'] as String)
.toList();
print(ids); // [#123456, #123456]
}
class JsonObjectTransformer extends StreamTransformerBase<String, dynamic> {
static final _openingBracketChar = '{'.codeUnitAt(0);
static final _closingBracketChar = '}'.codeUnitAt(0);
#override
Stream<dynamic> bind(Stream<String> stream) async* {
final sb = StringBuffer();
var bracketsCount = 0;
await for (final string in stream) {
for (var i = 0; i < string.length; i++) {
final current = string.codeUnitAt(i);
sb.writeCharCode(current);
if (current == _openingBracketChar) {
bracketsCount++;
}
if (current == _closingBracketChar && --bracketsCount == 0) {
yield json.decode(sb.toString());
sb.clear();
}
}
}
/*for example this line*/
//new File('test.txt').writeAsStringSync(sb.toString(), mode: FileMode.APPEND);
}
}
how can i do that?
There are multiple ways to do this but a simple way is to change the JsonObjectTransformer like this:
class JsonObjectTransformer extends StreamTransformerBase<String, dynamic> {
static final _openingBracketChar = '{'.codeUnitAt(0);
static final _closingBracketChar = '}'.codeUnitAt(0);
#override
Stream<dynamic> bind(Stream<String> stream) async* {
final sb = StringBuffer();
var bracketsCount = 0;
final ioSink = File('test.txt').openWrite(mode: FileMode.append);
await for (final string in stream) {
for (var i = 0; i < string.length; i++) {
final current = string.codeUnitAt(i);
sb.writeCharCode(current);
if (current == _openingBracketChar) {
bracketsCount++;
}
if (current == _closingBracketChar && --bracketsCount == 0) {
final dynamic jsonObject = json.decode(sb.toString());
ioSink.writeln(jsonObject['id'] as String);
yield jsonObject;
sb.clear();
}
}
}
await ioSink.flush();
await ioSink.close();
}
}
A more clean solution (since we want some separate of concern) would be to make use of the Stream in your main to write the ID's as each object are parsed. An example how to do that would be:
Future<void> main() async {
final file = File('test.txt').openWrite(mode: FileMode.append);
final ids = <String>[];
await File('sample.json')
.openRead()
.transform(const Utf8Decoder())
.transform<dynamic>(JsonObjectTransformer())
.map((dynamic json) => json['id'] as String)
.forEach((id) {
file.writeln(id);
ids.add(id);
});
await file.flush();
await file.close();
print(ids); // [#123456, #123456]
}

How to preserve state of Component of angular dart using RouterHook?

I am trying to preserve the state of a component upon changing route in Angular Dart. I stumbled upon the RouterHook abstract class which has an abstract function called canReuse.
Does implementing the RouterHook class preserve the state of the component and scroll position upon change of route?
I want to call an API once the component is added to fetch data. Yet, if a navigation occurs forward and back to that component, the app shouldn't call the API again (state preserved). It would be good to have a discussion about the life cycle of AngularDart apps.
#Component(
selector: 'blog-listing',
templateUrl: 'blog_listing_component.html',
styleUrls: [
'package:angular_components/css/mdc_web/card/mdc-card.scss.css',
'blog_listing_component.css',
],
providers: [
ClassProvider(BlogService),
],
directives: [
BlogDetailsComponent,
coreDirectives,
routerDirectives,
FixedMaterialTabStripComponent,
MaterialButtonComponent,
MaterialIconComponent,
MaterialSpinnerComponent,
],
)
class BlogListingComponent implements OnInit ,RouterHook{
List<String> categories = ["Category 1","Category 2", "Category 3"];
String currentCategory;
int currentTabIndex;
int skip;
int limit;
int blogCount;
List<Blog> currentBlogsPerCategory;
Blog currentBlog;
final Router _router;
final BlogService _blogService;
BlogListingComponent(this._blogService, this._router);
BaseState getBlogsState;
bool get isLoading => getBlogsState is LoadingState;
bool get isError => getBlogsState is ErrorState;
#override
void ngOnInit() async {
currentCategory = categories[0];
_blogService.getBlogsPerCategory(currentCategory);
BlogService.blogsBloc.listen((state) {
this.getBlogsState = state;
if (state is GotBlogsByCategoryState) {
currentBlogsPerCategory = state.blogs;
currentBlogsPerCategory = state.blogs;
}else if (state is GotMoreBlogsByCategoryState) {
currentBlogsPerCategory.clear();
currentBlogsPerCategory.addAll(state.blogs);
}
});
}
#override
void ngOnDestroy() async {
_blogService.dispose();
}
void onBeforeTabChange(TabChangeEvent event) {
skip = 0;
limit = 9;
currentBlogsPerCategory.clear();
currentTabIndex = event.newIndex;
currentCategory = categories[event.newIndex];
currentBlogsPerCategory = null;
_blogService.getBlogsByCategory(categories[event.newIndex], skip, limit);
}
void onNextPagePressed(int page) {
skip = (page-1) * 9;
limit = skip + 9;
_blogService.getMoreBlogsByCategory(currentCategory, skip, limit);
}
void onBlogDetailsPressed(Blog blog) {
BlogService.currentBlog = blog;
goToBlogDetails();
}
Future<NavigationResult> goToBlogDetails(){
_router.navigate(RoutePaths.blogDetails.toUrl());
}
#override
Future<bool> canActivate(Object componentInstance, RouterState oldState, RouterState newState) {
// TODO: implement canActivate
throw UnimplementedError();
}
#override
Future<bool> canDeactivate(Object componentInstance, RouterState oldState, RouterState newState) {
// TODO: implement canDeactivate
throw UnimplementedError();
}
#override
Future<bool> canNavigate() {
// TODO: implement canNavigate
throw UnimplementedError();
}
#override
Future<bool> canReuse(Object componentInstance, RouterState oldState, RouterState newState) async{
return true;
}
#override
Future<NavigationParams> navigationParams(String path, NavigationParams params) {
// TODO: implement navigationParams
throw UnimplementedError();
}
#override
Future<String> navigationPath(String path, NavigationParams params) {
// TODO: implement navigationPath
throw UnimplementedError();
}
}
RouterHook should no be implemented by the component route and should be injected to be found by the Router.
class MyHook implements RouterHook {}
#GenerateInjector([
routerProviders,
Provider(RouterHook, useClass: MyHook)
])
const providers = ng.providers$Injector;
runApp(MyAppComponent, providers);
However, for your use case, it's simpler to use the CanReuse mixin.
class BlogListingComponent with CanReuse implements OnInit {}
or
class BlogListingComponent implements OnInit, CanReuse {
#override
Future<bool> canReuse(RouterState oldState, RouterState newState) async {
return true;
}
}

Thread.sleep (change image) Java

I have two jlabels with an image.. I try to change the image in a label when the other is clicked.. (such as a game)..
I have a problem..When i write the Thread.sleep the image is not change..See the code:
public class Game extends JFrame{
private JLabel l1,l2;;
private boolean isClicked = false ,isClicked2 = false;
public Game(){
setLayout(new FlowLayout());
l1 = new JLabel(new ImageIcon(getClass().getResource("image1.png")));
add(l1);
l2 = new JLabel(new ImageIcon(getClass().getResource("image1.png")));
add(l2);
l1.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {
if(isClicked2){
l1.setIcon(new ImageIcon(getClass().getResource("image2.png")));
try {
Thread.sleep(1000);
l1.setIcon(new ImageIcon(getClass().getResource("image1.png")));
l2.setIcon(new ImageIcon(getClass().getResource("image1.png")));
isClicked2 = false;
isClicked = false;
}catch(InterruptedException ex){}
}
else{
l1.setIcon(new ImageIcon(getClass().getResource("image2.png")));
isClicked = true;
}
}#Override public void mouseEntered(MouseEvent e){}#Override public void mouseExited(MouseEvent e){}
});
l2.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {
if(isClicked){
try {
l2.setIcon(new ImageIcon(getClass().getResource("image2.png")));
Thread.sleep(1000);
l2.setIcon(new ImageIcon(getClass().getResource("image1.png")));
l1.setIcon(new ImageIcon(getClass().getResource("image1.png")));
isClicked = false;
isClicked2 = false;
}catch(InterruptedException ex){}
}
else{
l2.setIcon(new ImageIcon(getClass().getResource("image2.png")));
isClicked2 = true;
}
}#Override public void mouseEntered(MouseEvent e){}#Override public void mouseExited(MouseEvent e){}
});
}
public static void main(String[] args) {
Game g = new Game();
g.setTitle("Fint the same");
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g.pack();
g.setVisible(true);
}
}
Run it and first click the fisrt label.. After click the second label and the first will change image in 1 second but the seconf label NEVER!!
The changing of the images has to be done on the event thread (the thread used to process graphics events). Therefore setting the image will queue an appropriate event to be processed after your method returns. At that time though, the image has already changed back, because sleep()ing on the event thread doesn't allow any other events to be processed.
As dashrb said, don't sleep() the main thread, but schedule the flip back in a Timer:
if (isClicked) {
l2.setIcon(new ImageIcon(getClass().getResource("image2.png")));
new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
l2.setIcon(new ImageIcon(getClass().getResource("image1.png")));
l1.setIcon(new ImageIcon(getClass().getResource("image1.png")));
isClicked = false;
isClicked2 = false;
}
}).start();
} catch (final Exception ex) {
ex.printStackTrace();
}
} else {
...
You should not sleep() in these methods--they are invoked from the "event dispatch" thread, which handles all drawing events. If you're sleeping, then the thread can't be repainting your labels.
Rather than sleeping, change your image, then create a javax.swing.Timer task which will fire 1-second-from-now to change the images again as desired. The sample from koljaTM above uses a java.util.Timer, which runs in the "wrong" thread. This is his code, modified to use a SWING timer:
if (isClicked) {
try {
l2.setIcon(new ImageIcon(getClass().getResource("image2.png")));
javax.swing.Timer timer = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l2.setIcon(new ImageIcon(getClass().getResource("image1.png")));
System.out.println("image2 gone");
l1.setIcon(new ImageIcon(getClass().getResource("image1.png")));
isClicked = false;
isClicked2 = false;
}
});
timer.setRepeats(false);
timer.start();
} catch (final Exception ex) {
ex.printStackTrace();
}
} else {
...

Resources