[SimplePod] Storing Podcast Info

And Custom Themes!

If you haven’t seen my last post on the project, read it here.


The Last Two Weeks

I don’t know how many of you noticed, but it’s been almost 2 weeks since I last posted an update (well by the time I finish writing this, it will have been 2 weeks). Between the holidays and other activities related to them, I haven’t worked on the app way too much. And thanks to Anson VanDoren for keeping the feed busy while the rest of us haven’t been posting.

I have done three major things since my last post: Fixed the settings (for real this time (mostly)), add the ability to make a custom theme, and started using a database to store podcast feeds and data. The first two were actually done the day after my last post, but it was really late, so I held off making the post.

Settings Mini-Re(re)write

Last post I complained about widgets not updating properly, and having to make a almost-widget to get around that. Well turns out that failed horribly when I needed a setting to change the state of another setting, in this case a switch which disabled another setting. By the time I figured out the cause of the problem, I had spent way way too many hours trying to figure out why rebuilding a screen, and while “building“ the widget, it just didn’t and used the old state. Basically the constructor was getting called, but it was never creating a state to replace the old one, even though it should have been forced too.

So what was the end cause of all this pain: Keys. It took me forever to remember of something similar happening to me a year or two ago when I first started using flutter, and all I had to do was give it a unique key, so that when the constructor was ran, it would be giving a different key each time, telling it to build the new state.

When I first fixed this, I undid my sudo-widget class. However, I re-added it and made it more of a data model class that when it ran it’s build method, it would create the widget by passing itself. This made it so I didn’t have to list every single field in the stateful widget class (not the state class for the stateful widget).

In reality, it probably wasn’t much of an improvement on compactness, but adding another property has become easier.

So let’s compare:

Last Post:

class ColorSetting implements SettingWidget {
  final IconData icon;
  final String title;
  final String subtitle;
  final Function getDefaultValue;
  final Function getValue;
  final Function(Color) onChange;

  ColorSetting({ this.icon, this.title, this.subtitle, this.getValue, this.getDefaultValue, this.onChange});

  @override
  Widget build() => ColorSettingWidget(icon: icon, title: title, subtitle: subtitle,
      getValue: getValue, getDefaultValue: getDefaultValue, onChange: onChange);
}

class ColorSettingWidget extends StatefulWidget {

  final IconData icon;
  final String title;
  final String subtitle;
  final Function getDefaultValue;
  final Function getValue;
  final Function(Color) onChange;

  ColorSettingWidget({ this.icon, this.title, this.subtitle, this.getValue, this.getDefaultValue, this.onChange});

  @override
  _ColorSettingWidgetState createState() => _ColorSettingWidgetState(
      icon: icon, title: title, subtitle: subtitle, getValue: getValue, getDefaultValue: getDefaultValue, onChange: onChange);
}

class _ColorSettingWidgetState extends State<ColorSettingWidget> {

  final IconData icon;
  final String title;
  final String subtitle;
  final Function(Color) onChange;
  final Function getDefaultValue;

  Color currentValue;
  Color tempValue;

  _ColorSettingWidgetState({ this.icon, this.title, this.subtitle,
    Function getValue, this.getDefaultValue, this.onChange}) {
    currentValue = getValue();
  }
  // Rest of Class Not Shown
}

Now:

class ColorSetting implements SettingWidget{
  final IconData icon;
  final String title, subtitle;
  final Function getValue, getDefaultValue;
  final Function(Color) onChange;

  ColorSetting({ this.icon, this.title, this.subtitle, this.getValue, this.getDefaultValue, this.onChange});

  @override
  Widget build() => _ColorSettingWidget(this);
}

class _ColorSettingWidget extends StatefulWidget {

  final ColorSetting data;

  _ColorSettingWidget(this.data) : super(key: GlobalKey());

  @override
  _ColorSettingWidgetState createState() => _ColorSettingWidgetState(data);
}

class _ColorSettingWidgetState extends State<_ColorSettingWidget> {

  IconData icon;
  String title;
  String subtitle;
  Function(Color) onChange;
  Function getDefaultValue;

  _ColorSettingWidgetState(ColorSetting data) {
    icon = data.icon;
    title = data.title;
    subtitle = data.subtitle;
    getDefaultValue = data.getDefaultValue;
    onChange = data.onChange;

    currentValue = data.getValue();
  }

  Color currentValue;
  Color tempValue;

  // Rest of class not shown
}

Custom Theme

Once I finally got my settings working, I added support for creating a custom theme. The color picker I had chosen, isn’t perfect though. For example, it doesn’t have a pure black.

Screenshots: https://ibb.co/album/dtC3rF

Storing Podcast Info into a Database

I finally got around to it, yey! I was originally going to use sqflite, but then I saw a comment referencing moor, which is suppose to be a way to use databases with pure dart instead of SQL. Now, I have 0 problems writing stuff in SQL, it’s a fairly simple language, and I literally had 1½ years of classes on Oracle Databases, and have done projects that used databases before. That being said, I have a few reason why I’m going to me using moor, which is just a wrapper and generator for sqflite anyways:

  • While I have worked with databases all the time, SQLite, at least how it’s interfaced with sqflite is quite concluded. If someone could make a SQLite library that just had openDatabase(‘name‘)and .execute(‘query‘) that’s be great.

  • I already have a data model for this stuff parsing the RSS, so why not combine the table definitions and the data model into one thing.

  • Trying a new way. I’ve usually shied away from stuff like class serialization, especially when it came to stuff like JSON. I would always prefer doing getObject(‘name‘)over making a whole class and file just to put the JSON into that class, then get the info.

https://youtu.be/IBcRU1NM8Wc


Soumyajit Pathak picture

Welcome back!

Simplepod looks great.

Would love to know more about how you're using sqlite in Flutter and what improvements you think are the low hanging fruits that can addressed by releasing a helper package.

Minenash picture

I'm using the moor package, and so far, I haven't really reached any problems with it. And now that I know how the queries parameter in the @UseMoor annotation (by actually reading the documentation), I might just move my queries to that, as I ussually find pure SQL easier to read than using methods to build a query.

Though one weird thing that poped up, is the generator didn't like me using the .call() method instead of its syntax sugar equivalent (). That took me over an hour to figure out.

Though none of there are things that could be fixed with a helper package. Here's my database class rn. The parse method was originally written before Dart added helper methods, so I'll probably convert the rss helper methods into extension methods for XmlElement

Soumyajit Pathak picture

The extension methods in Dart is a great new addition. Thanks for the gist link. Will take a look.

Rhett Trickett picture

Welcome back Minenash! Nice to see you’re making progress on SimplePod, it’s looking great!

Tadhg picture

Great work!

Soumyajit Pathak picture

Welcome to Able. Look forward to seeing more of you :)

Minenash picture

Thanks! And welcome to able!