Small details that build taste in Flutter.

curated by Kamran BekirovKamran Bekirov

Keep the screen awake, but only where needed

On some pages users look at the screen for a long time without touching it: a video player, a live call, navigation, a reading page. Keep the screen awake there with wakelock_plus so it doesn't turn off in the middle.

But only on those pages. Don't turn it on in main.dart for the whole app. Users expect their phone to lock itself, for privacy and for battery.

Copy this small handler class:

import 'dart:async';
  
import 'package:wakelock_plus/wakelock_plus.dart';
  
class WakelockHandler {
  const WakelockHandler._();
  
  static StreamSubscription<bool>? _subscription;
  
  static void startSubscription(Stream<bool> source) {
    if (_subscription != null) return;
  
    _subscription = source.distinct().listen(_apply);
  }
  
  static Future<void> stopSubscription() async {
    await _subscription?.cancel();
    _subscription = null;
  
    await _apply(false);
  }
  
  static Future<void> enable() => _apply(true);
  
  static Future<void> disable() => _apply(false);
  
  static Future<void> _apply(bool value) {
    return WakelockPlus.toggle(enable: value);
  }
}

For screens that are pushed and popped, like a video player, use the manual methods:

@override
void initState() {
  super.initState();
  
  WakelockHandler.enable();
}
  
@override
void dispose() {
  WakelockHandler.disable();
  
  super.dispose();
}

That doesn't work for bottom bar tabs with IndexedStack: they get build once and never dispose, so the wakelock would never turn off. For those, pass the handler a stream that tells if any page needs the wakelock right now.

For example, in my prayer times app the screen stays awake in two places, the "Compass" tab and the "Read" tab inside "Quran" tab. So I combine the bottom bar tab with the inner tab:

Stream<bool> _stayAwake$() {
  return Rx.combineLatest2(
    rootTabCubit.stream.startWith(rootTabCubit.state),
    quranTabCubit.stream.startWith(quranTabCubit.state),
    (RootTab rootTab, QuranTab quranTab) {
      final bool isCompass = rootTab == .compass;
      final bool isReading = rootTab == .quran && quranTab == .read;
  
      return isCompass || isReading;
    },
  );
}

I start it once where the tabs are built:

WakelockHandler.startSubscription(_stayAwake$());

When the user opens the compass the wakelock turns on, when they leave it turns off.

Kamran Bekirov
Kamran Bekirov

Want this level of care in your Flutter apps?

Work With Me