2021-12-17 00:26:46

agreed with camlorn here. Do people not understand how to separate things? One of the first things I learned when I started with dart, Always, refactor, your, code. If you look at the opensourced flutter applications out there, you see that people do this all the time. Look for authpass on github and you will find that it's really readable. Even for a beginner, for the most part.

2021-12-17 00:42:39

@50 and @51
It's not that I don't know how to put things into their own components or whatever. I've used Pygame, Synthizer etc without issues. I just got lost in that mess of parenthesies (I can't keep track of all that in my head), and I'm still getting used to having an IDE do all the heavy work of inserting those for me.

2021-12-17 00:56:45

if you want to make it easier for yourself, you should indent your code. If you do this, you will be able to know where to insert parons based on indent levels. the thing I have trouble with is knowing when to insert commas, semicolons, that I can't keep track of in my head.

2021-12-17 01:02:23

Yeah, you do have to practice the nesting and stuff.  But you shouldn't have to deal with the deep nesting problem in the first place if you're doing this kind of thing right.  Whether your IDE helps you or not is irrelevant, because if you're doing that it's still probably bad code.

My Blog
Twitter: @ajhicks1992

2021-12-17 01:29:36

@52:
OK, so since I went through this particular thing while learning the principles of flutter my self, I think I have to explain some stuff, very quickly though since this is not the thread for it
First, because flutter doesn't necesarily follow any system UI rules, it can make its widgets look and behave in many ways, both to physical eyeballs and screen readers, that's why I managed to make the increment button be rounded in stead of square, hope I got the color right though, dk if black is good for a border or not, but that's neither here nor there.
To achieve that, in stead of having this huge widget object with dozens of properties and flags, each aspect of an onscreen controll is a separate widget, applying its effect on the widget its inclosing, a.k.a child. As you imagined, this can be recursive at infinitum, that's why I can have a focusable label with a text that's updating based on a variable.
If you know the ECS, you can think of the flutter framework, your handlers for events and all that as the system, then the end widgets you want who are just subtrees in the larger UI tree are considered entities, the various behaviours that make up each widget are, logically, the components of that controll. I DK if that's the best analogy, however that's one of the reasons I think rust should be a first class citison to the flutter ecosystem, as I think it could fit in there quite nicely. But meh, google being google, not gonna happen.
what you must keep in mind at all times is that, eventually, all widgets, no matter how nested, are actually classes, you are instantiating them in those parentheses with keyword arguments or something. That was the confusing part for me, I didn't know what I was actually doing, didn't know enough dart to realise that I'm calling constructors, I was trying to learn as much flutter related information as I could, but then I realised that I can't do one without at least a modest understanding of the other. I begun learning dart with this well, it's just the bastard of java, c#, maybe a bit of javascrypt/typescrypt thrown in there for good measure, how hard could it be? so don't do the same mistake as I did, at least go through the language tour.
Anyway, since those are classes, you can either write it all out, ending each constructor when it should(in a way like braces but with more ambiguous errors if you mess up), or simply store clumps of constructors so chained as a variable, like the separate component it actually is. If you think the outcome of what's gonna be displayed on screen depends on some other parameters, then better make it in to a proper widget, with a widget class and everything, you'll thank your self later. Don't think if you want to make a stateful or stateless widget, since if you have a supported ide, the conversion can be done automatically when you decide one over the other. As a rule of thumb, try to keep as many of your widgets as possible stateless, since those are lighter and build considerably faster, plus don't have a state object that has to be rebuilt and not used properly if the widget is made stateful in error, so try to keep that in mind.
actually, I didn't write it in any supported editor or anything, the only thing I used was notepad and the skil I gained with braces to manage those parens, they are nothing more than braces to me. Could I have split that thing further, possibly, however maybe not with widget classes, perhaps just simple variables would be enough. However the point is, this is learnable, eventually. Now, with a supported editor, indeed you get such wrappings with other widgets, extracting of parts of the tree as a separate widget and so on, however though they are a productivity booster, I recommend you don't use them while learning to cope with this stuff.
another tip for you! do you have a pluggin for your editor that navigates you by indentation levels? if so, it can be really useful here as well. Put your cursor at the beginning of a widget, press the shortcut to go to the next line with same level of indentation, boom, you're at the end of that widget, no matter how deep the hierarchy goes.
back to the topic at hand however, does anyone know why live regions don't work here, or is it the case for everyone? can someone else confirm this?

2021-12-17 01:58:10

I like the tree concept. That’s why I always go back to flutter. And it just reads so nicely to me. Tip, if you are going to have an application with multiple screens. I recommend making a screens folder and putting your app screens in different files

2021-12-17 02:42:19

OK, so I've played with live regions on Windows.

In short: They don't seem to work. I managed to fudge them into working by making the counter text focusable, and adding a shortcut key to increment it. Then, it doesn't need to be live, because it reads anyways, so should be good enough for games until someone (me tomorrow if nobody beats me to it) creates an issue.

Anyways, for the interested, here's the code I used:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class IncrementIntent extends Intent {
  /// Create an instance.
  const IncrementIntent();
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Shortcuts(
              shortcuts: const {
                SingleActivator(LogicalKeyboardKey.space): IncrementIntent()
              },
              child: Actions(
                actions: {
                  IncrementIntent: CallbackAction(
                    onInvoke: (intent) => _incrementCounter(),
                  )
                },
                child: Focus(
                  child: Text(
                    '$_counter',
                    style: Theme.of(context).textTheme.headline4,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
-----
I have code on GitHub

2021-12-17 09:25:39

OK, so the workaround for now is to declare the label itself both focusable and clicable with space, then the sr would react as if the text under the cursor just changed, in which case it'll be read anyway as it is for most standard controls when this happens. Hacky workaround that I hope will go away soon as things progress, however it's at least something. Btw, why did you have to use that intent thing, couldn't you use a gesture recogniser, or is that mobile and therefore touchscreen only?

2021-12-17 21:09:21

Hey folks, wanted to promote a relevant project that's very early in development but promising:

https://accesskit.dev is working on being an accessibility façade for platform-specific accessibility APIs. With AccessKit, existing and custom UI toolkits can essentially push their data to the provided schemas, and get screen reader and other accessibility for free on Windows, Linux, macOS, Android, iOS, and the web. The plan for the web-based version is to maintain a parallel DOM with HTML widgets, and pull changes from that.

Written in Rust, with plans for a C-compatible API, as well as Java bindings for Android. There are currently a few examples that basically create a self-voicing UI by drawing nothing and spitting out accessible objects for NVDA to consume. There is also a basic egui PoC showing that it can work with immediate-mode UIs as well. Currently supports only a few widgets because it's just being used to prove out the concept.

Ambitious, yes. But I know the developer, and if anyone can pull it off, he can. He's also got a bit of funding through a Google contract, and I believe there's a volunteer working on the Linux support currently though I haven't seen much on that front yet. So it's definitely not just a weekend project by someone who doesn't get how hard it is to pull off, even if it will take a lot of time. I think there are also plans to pursue other contracts from the angle that it's easier to make your UI work everywhere with AccessKit, so those rare unicorn grants for software accessibility might be best spent raising the tide that lifts all boats, as it were.

I'll definitely be integrating it into my games as soon as it becomes practical to do so. The egui prototype already implements most of what I'm currently using in System Fault, so making the UI screen reader accessible under Windows at least is probably closer than you might imagine.

2021-12-17 21:18:34

yeah, I'm sort of watching that.  Hopefully we can solve this problem generally.  Dart did desktops by ripping Chrome's equivalent of AccessKit, which is how they were able to move as quickly as they have.  Figuring out if I can fund this some is something I keep failing to look into, but I should bump that up my priority list.

My Blog
Twitter: @ajhicks1992

2021-12-17 22:44:39

Yeah, I opened an issue on SixtyFPSs GH repo and they pointed to me too and thought that waiting for that to be relatively stable and then going after that for accessibility would be better than rolling their own. I haven't looked too deeply into it but might look into helping out with the Linux and BSD side of things.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-12-17 22:55:52

For those who don't know, it's by the lead developer for System Access.

My Blog
Twitter: @ajhicks1992

2021-12-17 23:02:02

@59
It's not clickable by space, that's the thing. It's just that the Shortcuts class lets you assign shortcut keys to intents, then Actions binds Intent subclasses to callbacks.

To read more, there's this page.

-----
I have code on GitHub

2021-12-18 01:16:44

Okay... One question... Why are they using boxed &strs? This seems like a huge design flaw (and is unnecessary, you have Strings, and Strings can be passed over FFI via the cxx crate).

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-12-18 01:44:04

@64
So! I haven't looked at the code, but here is a set of fun things about Rust!  If you do:

HashMap<Box<String>, Whatever>

Then you can't actually look things up by &str and have to have actual string objects as your key.  This holds true for most container types.  So for example my subcrate for sounds in ammo is using it to get around this.

It's not actually as big a deal as it looks, though.  You can perform all immutable string operations on that, and iirc getting back to a String in contexts where you can move out is super easy.

Specifically you typically have something along the lines of:

fn get<Q>(&self, key: Q) -> V where K: Borrow<Q>

Which lets you look up anything you can borrow as the key.  But it's not really possible to make borrow transitive, especially if for example you want to let a type be borrowed as multiple things, because then you hit overlapping impls and the lack of stable specialization.  As an example of where this gets gnarly, consider Cow sometime.

you might want to write your bounds to say that you're willing to accept anything which can be borrowed as something the key can be borrowed as, but apart from that being so complicated that I can't write the bounds without looking at like 5 docs pages, you end up with something which can't play nice with type inference because it won't necessarily know which of the things to borrow as on both sides, and then you end up with huge blocks instead of simple .get calls or whatever else.

Also Box<String> has a memory overhead because actually what gets boxed is the string struct, and the string struct then contains a pointer to the actual data, which is a double allocation for an intermediate object that's like 16 bytes in size.  I'm reasonably sure that Box<str> is only one, and the size is stored inline in the box.  For small strings, that's a huge savings (as in literally half).

My Blog
Twitter: @ajhicks1992

2021-12-18 03:00:29

@65, I know about that problem, but I wasn't say box the string, I was saying just use a pure String struct instead of Box<str>. And they have on struct fields, not in collections (from what I can tell anyway just looking at the schema).

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-12-18 03:06:03

@66
But that's one of my points.  Box<String> is pointer to String struct then pointer to String contents, a double lookup and allocation of a very small object on the heap.  Box<str> also has the advantage that you can't accidentally append to it or something and invalidate references you gave out to C earlier.  I'm not going to bother digging through their code to determine how right you are or aren't, but it's not an unreasonable design choice in the slightest and for some reason you have jumped straight to criticizing it.

My Blog
Twitter: @ajhicks1992

2021-12-18 03:32:41

@67, I criticized it because the way they're using it from what I can tell doesn't really seem to benefit them all that much. Your explanation makes things a bit clearer, though. It doesn't help that I haven't seen that pattern all that often myself.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-12-18 03:54:00

but like, won't it be better to get rid of Box at all, since String is an owned type anyway? or is it because String doesn't implement sized on its own? I'm sure though, that there is a crate to allow it to be passed across the c ffi if that's the goal.

2021-12-18 05:41:48

@69
I mean if we're going to do rust learning, sure.  The problem with String is that if you ever forget and do mystring.push("bla") the address of the string changes.  This really just depends what tradeoffs you're going for.  It's a good way to make sure at the type level that no string moves once created: the only way to get back to String is to move out of the box.

It's not necessarily the right choice, without doing a bunch of digging and thought and stuff I am not going to comment on what they're doing, but it's certainly not a bad choice.  And it's extra certainly not a bad choice if you use it with Arc because Arc<String> is kind of terrible any way you look at it and has weird ergonomics.

My Blog
Twitter: @ajhicks1992

2021-12-20 13:17:01

Another issue that people might be able to shed more light on than I:

https://github.com/flutter/flutter/issues/95556

In short: Text fields don't behave nicley. The minimal code in there should give you an idea. Not sure if this is a UWP thing though (as I'm reasonably sure that's what Flutter is making).

-----
I have code on GitHub

2021-12-20 13:25:02

nope, it's not uwp. I made an app called autoaccess back in the day, cross platform and all, with the xamarin.forms thing. For windows, I went with uwp. Thing is, the only issue in text fields was that blank lines weren't read, in stead the last non-empty line was spoken, hell knows what bug was that. However, the character thingy is a new one, it's certainly flutter specific.

2021-12-20 16:36:55

@71
Flutter isn't producing UWP, it's producing a completely custom tree.  Anything weird is their fault.

My Blog
Twitter: @ajhicks1992

2021-12-21 14:59:08

@72 and 73
Thought so, but thought it was worth mentioning, since last time I used the Microsoft Store (bloody ages ago), it was an odd experience.

-----
I have code on GitHub

2022-01-29 18:58:08

Sorry to revive this thread, but the tab order has been fixed. I have wrote a test software which displays some lists, buttons, static tests and textboxes. Everything is OK except that text boxes are a bit broken, atleast with ZDSR (No NVDA on my machine now). The bug is that when there is one line of text, I cannot navigate in the textbox. But when I create a new line, everything is normal.

If you want to contact me, do not use the forum PM. I respond once a year or two, when I need to write a PM myself. I apologize for the inconvenience.
Telegram: Nuno69a
E-Mail: nuno69a (at) gmail (dot) com