How to use a Variable from one class in another Class? - variables

I want to use the ´bool DrawMode´ inside my ChangeDrawModeState class.
I need Something like ´GridState.drawMode´ but that does not work(drawMode is defined in GridState).
In the end I need to change the variable drawMode, if the RaisedButton gets Pressed. I'm not sure how to do this, cause the setState isnt working in the ChangeDrawModeState class as well. But isn't there a simple way to build a Button which turns a bool from True to false(or the other way around)?
class ChangeDrawMode extends StatefulWidget{
#override
ChangeDrawModeState createState(){
return new ChangeDrawModeState();
}
}
class ChangeDrawModeState<ChangeDrawMode>{
#override
Widget build(BuildContext context) {
return new RaisedButton(
child: new Text('Change Mode'),
textColor: Colors.white,
color: GridState.drawMode ? Colors.grey : Colors.blue,//HERE
onPressed: () =>setState(() => drawMode = !drawMode) //and HERE drawMode does not work
);
}
}
class Grid extends StatefulWidget {
#override
GridState createState() {
return new GridState();
}
}
class GridState extends State<Grid> {
bool drawMode = false;
final Set<int> selectedIndexes = Set<int>();
final key = GlobalKey();
final Set<_Foo> _trackTaped = Set<_Foo>();
_detectTapedItem(PointerEvent event) {
final RenderBox box = key.currentContext.findRenderObject();
final result = BoxHitTestResult();
Offset local = box.globalToLocal(event.position);
if (box.hitTest(result, position: local)) {
for (final hit in result.path) {
/// temporary variable so that the [is] allows access of [index]
final target = hit.target;
if (target is _Foo /*&& !_trackTaped.contains(target)*/) {
_trackTaped.add(target);
_selectIndex(target.index);
}
}
}
}
_selectIndex(int index) {
setState(
() {
if(selectedIndexes.contains(index)&&drawMode==false){
selectedIndexes.remove(index);
}
else if(drawMode==true){
selectedIndexes.add(index);
}
});
}

You can use InheritedWidget to update data and therefore widget state from any part of the app
Here is an example

Related

recyclerview filter in is not working in android studio

I have coded getFilter() in adapter class and onQueryTextChange in mainactivity but don't know whats the prob it is not filtering nor searching please help I need to implement a search filter RecyclerView the list must be filtered while typing.
This part is in my Mainactivity
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) item.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
BalanceReportAdapter myClass = new BalanceReportAdapter(jsonResponses,
BalanceReport.this);
myClass.getFilter().filter(newText);
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
This part is in my Adapter.class
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constaint) {
List<BalanceReportModel> filteredList = new ArrayList<>();
if (constaint.toString().isEmpty()) {
filteredList.addAll(retrievedResponses);
Log.e("you are here1",filteredList.toString());
} else {
for (BalanceReportModel patient : retrievedResponsesAll) {
if
(patient.getcustomer().toLowerCase().contains(constaint.toString().toLowerCase()))
{
filteredList.add(patient);
}
}
Log.e("you are here2",retrievedResponses.toString());
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void publishResults(CharSequence constraint, FilterResults filterResults) {
Log.e("you are here3",filterResults.toString());
retrievedResponses.clear();
retrievedResponses.addAll((Collection<? extends BalanceReportModel>) filterResults.values);
notifyDataSetChanged();
}
};
I have tried several times but not yet succeeded Please someone help me. Is there any other way to make it work?
Correct me if i am wrong
It seems you are creating a new adapter each time in your onQueryTextChange
This instance of adapter is not assigned to recyclerView anywhere after that. I would recommend having one instance of adapter somewhere at the top-level and just call for that instance, and .filter logic

Flutter API calls with Future Builder returns error when future method called inside initState()

I was trying to call APIs that need to be loaded the first time the page is built. So I used FutureBuilder and written an initState call. Every page works fine but only on one page, I faced an issue with context. Then I understood about didChangeDependencies. Which is the correct way to call APIs from another class (that need to access the current widget context too).
Where should I call calculatorFuture = getParkingAreaList(); in initState() or didChangeDependencies().
String TAG = "CalculatorPage";
class CalculatorPage extends StatefulWidget {
const CalculatorPage({
Key key,
}) : super(key: key);
#override
_CalculatorPageState createState() => _CalculatorPageState();
}
class _CalculatorPageState extends State<CalculatorPage> {
Future calculatorFuture;
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
calculatorFuture = getParkingAreaList();
}
Future<bool> apiCallHere() async {
print('apiCallHere');
String lang = getCurrentLanguage(context);
print('going to call res');
var res = await HttpHandler.apiCallFromHttpHanlderClass(context);
if (res == null) {
print('res is null');
showToast(LanguageLocalization.of(context).getTranslatedValue('generic_failure_message'));
return false;
}
print(res);
if(res["STATUS_CODE"] == 1) {
print('apiCallHere status code = 1');
apiData = res['someData'];
return true;
}
else {
print('apiCallHere status code !=1');
return false;
}
}
#override
Widget build(BuildContext context) {
print(TAG);
return Scaffold(
appBar: commonAppBar(context: context, title: 'calculator'),
body: FutureBuilder(
future: calculatorFuture,
builder: (context, snapshot) {
print(snapshot);
if (snapshot.hasError || (snapshot.hasData && !snapshot.data)) {
print('has error');
print(snapshot.hasError ? snapshot.error : "unable to load data");
return unableToLoadView(context);
} else if (snapshot.hasData && snapshot.data) {
print('completed future');
return Container(
margin: commonPagePadding,
child: ListView(
children: <Widget>[
//some widget that deals with apiData
],
)
);
} else {
print('loading');
return showLoaderWidget(context);
}
},
)
);
}
}
you can call future function in didchangedependenci changing like that
#override
Future <void> didChangeDependencies() async{
super.didChangeDependencies();
calculatorFuture = await getParkingAreaList();
}
If you want to call the API once when a page loads up just place the future inside initState like the example below.
#override
void initState() {
super.initState();
calculatorFuture = getParkingAreaList();
}

Why is data not being refreshed in StreamBuilder?

I am making a movie list application in Flutter and when I open the app I am displaying most-viewed movies list. When I click a button, I fetch new data and add it to the sink which is then sent to the StreamBuilder and should refresh the screen with new data.
But that doesn't happen. I cannot fathom why!
Here is my code for the Repository:
class MoviesRepository {
final _movieApiProvider = MovieApiProvider();
fetchAllMovies() async => _movieApiProvider.fetchMovieList();
fetchAllSimilarMovies(genreIdeas) async => await _movieApiProvider.fetchMoviesLikeThis(genreIdeas);
fetchTopRatedMovies() async => await _movieApiProvider.fetchTopRatedMovieList();
}
Here is my code for bloc:
class MoviesBloc {
final _moviesRepository = MoviesRepository();
final _moviesFetcher = BehaviorSubject<Result>();
Sink<Result> get allMovies => _fetcherController.sink;
final _fetcherController = StreamController<Result>();
Observable<Result> get newResults => _moviesFetcher.stream;
fetchAllMovies() async {
Result model = await _moviesRepository.fetchAllMovies();
allMovies.add(model);
}
fetchTopRatedMovies() async{
Result model = await _moviesRepository.fetchTopRatedMovies();
allMovies.add(model);
}
dispose() {
_moviesFetcher.close();
_fetcherController.close();
}
MoviesBloc() {
_fetcherController.stream.listen(_handle);
}
void _handle(Result event) {
_moviesFetcher.add(event);
}
}
final bloc = MoviesBloc();
UPDATE
And here is my code for the StreamBuilder:
class HomeScreenListState extends State<HomeScreenList> {
#override
void initState() {
super.initState();
print("init");
bloc.fetchAllMovies();
}
#override
void dispose() {
super.dispose();
bloc.dispose();
}
#override
Widget build(BuildContext context) {
return StreamBuilder<Result>(
builder: (context, snapshot) {
if (snapshot.hasData) {
print("new data is here");
return buildList(snapshot);
} else if (snapshot.hasError) {
return Text('Error!!');
}
return Center(
child: CircularProgressIndicator(),
);
},
stream: bloc.newResults,
);
}
}
And this is the button that triggers to get new data and add it to the sink:
child: RaisedButton(onPressed: () {
bloc.fetchTopRatedMovies();
},
This button fetches top-rated movies and add to the same sink. Now the StreamBuilder should pick up the new data as I think.
Where is the problem??
You can use Equatable alongside your BLoC implementation to manage state changes on your screen. Here's a guide that I suggest trying out.

composing html file in aurelia

I'd like to achieve something similar as "include" in android but in aurelia:
How to inject a plain html file content into my view, with binding evaluated within the parent View, and without using a custom element?
Binding innerhtml is not enough as, according to the doc, the bindings expressions are bypassed.
As already said by Ashley, using <compose view="./your-view.html"></compose> element will work with an existing HTML file and it will inherit the parent context.
If you want to compose HTML dynamically (from a file, database, or built-up programmatically) then using the ViewCompiler will give you the best performance and flexibility, as this is one layer less than compose compared to how aurelia builds custom elements internally.
I gave a similar answer to a different (but related) question here:
Aurelia dynamic binding
You'd use the text plugin to load your HTML file as text into a variable, and then pass that to the ViewCompiler. I have a custom element for this which, in terms of performance, is probably not better than compose but it does allow for more control when working with raw html as input and you could do your own performance optimizations specific to your situation as needed:
import * as markup from "text!./your-element.html";
export class SomeViewModel {
constructor() {
this.markup = markup;
}
}
And the view:
<template>
<dynamic-html html.bind="markup"></dynamic-html>
</template>
For completeness sake, here is the custom element I encapsulated the ViewCompiler in:
import {
customElement,
TaskQueue,
bindable,
ViewCompiler,
ViewSlot,
View,
ViewResources,
Container,
ViewFactory,
inlineView,
inject,
DOM
} from "aurelia-framework";
#customElement("dynamic-html")
#inlineView("<template><div></div></template>")
#inject(DOM.Element, TaskQueue, Container, ViewCompiler)
export class DynamicHtml {
#bindable()
public html: string;
public element: HTMLElement;
private tq: TaskQueue;
private container: Container;
private viewCompiler: ViewCompiler;
private runtimeView: View;
private runtimeViewSlot: ViewSlot;
private runtimeViewFactory: ViewFactory;
private runtimeViewAnchor: HTMLDivElement;
constructor(element, tq, container, viewCompiler) {
this.element = <HTMLElement>element;
this.tq = tq;
this.container = container;
this.viewCompiler = viewCompiler;
}
public bindingContext: any;
public overrideContext: any;
public bind(bindingContext: any, overrideContext: any): void {
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
if (this.html) {
this.htmlChanged(this.html, undefined);
}
}
public unbind(): void {
this.disposeView();
this.bindingContext = null;
this.overrideContext = null;
}
public needsApply: boolean = false;
public isAttached: boolean = false;
public attached(): void {
this.runtimeViewAnchor = <HTMLDivElement>this.element.firstElementChild;
this.isAttached = true;
if (this.needsApply) {
this.needsApply = false;
this.apply();
}
}
public detached(): void {
this.isAttached = false;
this.runtimeViewAnchor = null;
}
private htmlChanged(newValue: string, oldValue: void): void {
if (newValue) {
if (this.isAttached) {
this.tq.queueMicroTask(() => {
this.apply();
});
} else {
this.needsApply = true;
}
} else {
if (this.isApplied) {
this.disposeView();
}
}
}
private isApplied: boolean = false;
private apply(): void {
if (this.isApplied) {
this.disposeView();
}
this.compileView();
}
private disposeView(): void {
if (this.runtimeViewSlot) {
this.runtimeViewSlot.unbind();
this.runtimeViewSlot.detached();
this.runtimeViewSlot.removeAll();
this.runtimeViewSlot = null;
}
if (this.runtimeViewFactory) {
this.runtimeViewFactory = null;
}
if (this.runtimeView) {
this.runtimeView = null;
}
this.isApplied = false;
}
private compileView(): void {
this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);
this.runtimeView = createView(this.runtimeViewFactory, this.container);
this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);
this.runtimeViewSlot.add(this.runtimeView);
this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);
this.runtimeViewSlot.attached();
this.isApplied = true;
}
}
function createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {
if (!html.startsWith("<template>")) {
html = `<template>${html}</template>`;
}
let viewResources: ViewResources = container.get(ViewResources);
let viewFactory = viewCompiler.compile(html, viewResources);
return viewFactory;
}
function createView(viewFactory: ViewFactory, container: Container): View {
let childContainer = container.createChild();
let view = viewFactory.create(childContainer);
return view;
}
function createViewSlot(containerElement: Element): ViewSlot {
let viewSlot = new ViewSlot(containerElement, true);
return viewSlot;
}

Aurelia dynamic binding

I've created a custom element that generates tabular data. For good reasons, this generates the actual HTML and inserts into the DOM without using a template.
I need to attach click observers to specific elements to I can run a function in the custom element in response to a click. If using a template, I'd use click.delegate, but I can't use that with generated HTML.
How do you attach an event handler with Aurelia other than by using jQuery?
I know this answer is late, but in case this hasn't been (properly) solved yet and/or someone else finds this in the future:
In order to make any aurelia behavior work in dynamically generated HTML, you need to compile that HTML.
I have worked on a custom element (based on how aurelia's enhance and compose work) that allows you to pass in a string of HTML and it will then be compiled, so that any behaviors like bindables, custom elements / attributes will just work. It will also re-compile when the html changes.
Here's an example: https://gist.run?id=1960218b52ba628f73774822aef55ad7
src/app.html
<template>
<dynamic-html html.bind="dynamicHtml"></dynamic-html>
</template>
src/app.ts
export class App {
public dynamicHtml: string = `
<button click.delegate="handleClick()">Click me</button>
`;
public handleClick(): void {
alert("Hello!")
}
}
src/dynamic-html.ts
import {
customElement,
TaskQueue,
bindable,
ViewCompiler,
ViewSlot,
View,
ViewResources,
Container,
ViewFactory,
inlineView,
inject,
DOM
} from "aurelia-framework";
#customElement("dynamic-html")
#inlineView("<template><div></div></template>")
#inject(DOM.Element, TaskQueue, Container, ViewCompiler)
export class DynamicHtml {
#bindable()
public html: string;
public element: HTMLElement;
private tq: TaskQueue;
private container: Container;
private viewCompiler: ViewCompile;
private runtimeView: View;
private runtimeViewSlot: ViewSlot;
private runtimeViewFactory: ViewFactory;
private runtimeViewAnchor: HTMLDivElement;
constructor(element, tq, container, viewCompiler) {
this.element = <HTMLElement>element;
this.tq = tq;
this.container = container;
this.viewCompiler = viewCompiler;
}
public bindingContext: any;
public overrideContext: any;
public bind(bindingContext: any, overrideContext: any): void {
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
if (this.html) {
this.htmlChanged(this.html, undefined);
}
}
public unbind(): void {
this.disposeView();
this.bindingContext = null;
this.overrideContext = null;
}
public needsApply: boolean = false;
public isAttached: boolean = false;
public attached(): void {
this.runtimeViewAnchor = this.element.firstElementChild;
this.isAttached = true;
if (this.needsApply) {
this.needsApply = false;
this.apply();
}
}
public detached(): void {
this.isAttached = false;
this.runtimeViewAnchor = null;
}
private htmlChanged(newValue: string, oldValue: void): void {
if (newValue) {
if (this.isAttached) {
this.tq.queueMicroTask(() => {
this.apply();
});
} else {
this.needsApply = true;
}
} else {
if (this.isApplied) {
this.disposeView();
}
}
}
private isApplied: boolean = false;
private apply(): void {
if (this.isApplied) {
this.disposeView();
}
this.compileView();
}
private disposeView(): void {
if (this.runtimeViewSlot) {
this.runtimeViewSlot.unbind();
this.runtimeViewSlot.detached();
this.runtimeViewSlot.removeAll();
this.runtimeViewSlot = null;
}
if (this.runtimeViewFactory) {
this.runtimeViewFactory = null;
}
if (this.runtimeView) {
this.runtimeView = null;
}
this.isApplied = false;
}
private compileView(): void {
this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);
this.runtimeView = createView(this.runtimeViewFactory, this.container);
this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);
this.runtimeViewSlot.add(this.runtimeView);
this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);
this.runtimeViewSlot.attached();
this.isApplied = true;
}
}
function createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {
if (!html.startsWith("<template>")) {
html = `<template>${html}</template>`;
}
let viewResources: ViewResources = container.get(ViewResources);
let viewFactory = viewCompiler.compile(html, viewResources);
return viewFactory;
}
function createView(viewFactory: ViewFactory, container: Container): View {
let childContainer = container.createChild();
let view = viewFactory.create(childContainer);
return view;
}
function createViewSlot(containerElement: Element): ViewSlot {
let viewSlot = new ViewSlot(containerElement, true);
return viewSlot;
}