Nitish Aggarwal

The First Evaluations

The first Week focussed on adding enhancements for the mobile_app.. The first one being adding localizations to the app. Just an overview, the localizations logic lives in lib/locale/locales.dart and generated arb and messages in lib/l10n/

AppLocalizations are handled the InheritedWidget way, hence have an of method which returns Localizations.of<AppLocalizations>(context, AppLocalizations). flutter’s Localization defines the Locale for its child and the localized resources that the child depends on. Localized resources are loaded by the AppLocalizationDelegate which is just a collection of localized resources. The most important of the methods of the delegate being the load method, which is responsible for returning localized messages.

class AppLocalizations {
  static Future<AppLocalizations> load(Locale locale) {
    final name =
        locale.countryCode.isEmpty ? locale.languageCode : locale.toString();

    final localeName = Intl.canonicalizedLocale(name);

    return initializeMessages(localeName).then((bool _) {
      Intl.defaultLocale = localeName;
      return AppLocalizations();
    });
  }

  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }

  String get title {
    return Intl.message(
      'CircuitVerse',
      name: 'title',
      desc: 'Title for CircuitVerse Mobile',
    );
  }
}

class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) => ['en'].contains(locale.languageCode);

  @override
  Future<AppLocalizations> load(Locale locale) => AppLocalizations.load(locale);

  @override
  bool shouldReload(AppLocalizationsDelegate old) => false;
}

# generate arb resources for the getters defined AppLocalizations
flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/locale/locales.dart

# generate bunch of dart files that contains switching logic thru the above generated arb files
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/intl_en.arb lib/l10n/intl_messages.arb lib/locale/locales.dart

The localizations delegates are registered in the MaterialApp's localizationsDelegates.

return MaterialApp(
  ...
  localizationsDelegates: [
    AppLocalizationsDelegate(),
    GlobalMaterialLocalizations.delegate,
    // For RTL Support
    GlobalWidgetsLocalizations.delegate,
  ],
  supportedLocales: [
    Locale('en', ''),
  ],
  ...
)

And there we go, AppLocalizations.of(context).title gives you the localized title in onGenerateTitle.

The next thing was adding pedantic as analysis_options.yaml for improved code quality, and Dart static analysis.

The one thing i am proud of using this package is not that it is used in Google internally but having a better understanding of the new, const & final variables. The gist of which is the following :

The second Week focussed on perfecting the API and adding some enhancements.. Some of the notable one’s being adding send_reset_password_instructions & GET public_key.pem to decode the data encoded in the token.

# POST api/v1/password/forgot
def forgot_password
  @user = User.find_by!(email: params[:email])
  # Devise is amazing :P
  @user.send_reset_password_instructions
  render json: { message: "password reset instructions sent to #{@user.email}" }
end

# GET /public_key.pem
def public_key
  public_key = File.open(Rails.root.join("config", "public.pem"), "r:UTF-8")
  send_file public_key
end

For the Group’s API #1462 added conter_cache to cache group_member_count in Groups to avoid N+1 queries.

First things first, counter_cache: true in group_member.rb.

class GroupMember < ApplicationRecord
  ...
  belongs_to :group, counter_cache: true
end

Add a column in groups_table that would works as a counter for number of group_members.

def change
  add_column :groups, :group_members_count, :integer
end

Resetting counters for already existing records.

def change
  Group.all.each do |group|
    Group.reset_counters(group.id, :group_members)
  end
end

Now, group.group_members.count -> group.group_members.size, this is not much change, but hey check the logs, you’ll realize :P

Just another optimization, thanks @tachyons

# BEFORE -> O(N)
project = assignment.projects.find { |p| p.author_id == params[:current_user].id }

# AFTER -> O(1)
project = assignment.projects.find_by(author_id: params[:current_user].id)

#1473, #1477, #1482 were merged with some minor tweaks.. Yay!! The API docs would now live in CircuitVerse itself, updated the docs in view of the final API, for more details refer #1512.

This wraps it up for the first evaluation :fingers_crossed:

See Ya Next Week