2021-03-16 19:54:48 +00:00
import ' dart:collection ' ;
2021-03-09 01:23:37 +00:00
import ' dart:ui ' ;
import ' dart:core ' ;
import ' package:flutter/material.dart ' ;
import ' package:package_info_plus/package_info_plus.dart ' ;
2021-03-10 17:40:14 +00:00
import ' opaque.dart ' ;
2021-03-24 23:35:24 +00:00
const TapirGroupsExperiment = " tapir-groups-experiment " ;
2021-06-24 07:36:41 +00:00
enum DualpaneMode {
Single ,
Dual1to2 ,
Dual1to4 ,
CopyPortrait ,
}
2021-03-16 19:54:48 +00:00
/// Settings govern the *Globally* relevant settings like Locale, Theme and Experiments.
/// We also provide access to the version information here as it is also accessed from the
/// Settings Pane.
2021-03-09 01:23:37 +00:00
class Settings extends ChangeNotifier {
Locale locale ;
2021-05-25 00:11:39 +00:00
late PackageInfo packageInfo ;
2021-03-10 17:40:14 +00:00
OpaqueThemeType theme ;
2021-06-04 18:13:52 +00:00
// explicitly set experiments to false until told otherwise...
bool experimentsEnabled = false ;
2021-03-16 19:54:48 +00:00
HashMap < String , bool > experiments = HashMap . identity ( ) ;
2021-06-24 07:36:41 +00:00
DualpaneMode _uiColumnModePortrait = DualpaneMode . Single ;
DualpaneMode _uiColumnModeLandscape = DualpaneMode . CopyPortrait ;
2021-03-10 17:40:14 +00:00
2021-06-23 00:03:36 +00:00
bool blockUnknownConnections = false ;
2021-04-06 20:33:44 +00:00
2021-03-16 19:54:48 +00:00
/// Set the dark theme.
2021-03-10 17:40:14 +00:00
void setDark ( ) {
2021-06-24 17:59:23 +00:00
theme = OpaqueDark ( ) ;
2021-03-10 17:40:14 +00:00
notifyListeners ( ) ;
}
2021-03-16 19:54:48 +00:00
/// Set the Light theme.
2021-03-10 17:40:14 +00:00
void setLight ( ) {
2021-06-24 17:59:23 +00:00
theme = OpaqueLight ( ) ;
2021-03-10 17:40:14 +00:00
notifyListeners ( ) ;
}
2021-03-16 19:54:48 +00:00
/// Get access to the current theme.
2021-03-10 17:40:14 +00:00
OpaqueThemeType current ( ) {
return theme ;
}
2021-06-04 18:13:52 +00:00
/// isExperimentEnabled can be used to safely check whether a particular
/// experiment is enabled
bool isExperimentEnabled ( String experiment ) {
if ( this . experimentsEnabled ) {
if ( this . experiments . containsKey ( experiment ) ) {
// We now know it cannot be null...
return this . experiments [ experiment ] ! = = true ;
}
}
return false ;
}
2021-03-16 19:54:48 +00:00
/// Called by the event bus. When new settings are loaded from a file the JSON will
/// be sent to the function and new settings will be instantiated based on the contents.
2021-03-10 17:40:14 +00:00
handleUpdate ( dynamic settings ) {
2021-03-16 19:54:48 +00:00
// Set Theme and notify listeners
2021-03-10 17:40:14 +00:00
if ( settings [ " Theme " ] = = " light " ) {
this . setLight ( ) ;
} else {
this . setDark ( ) ;
}
2021-03-16 19:54:48 +00:00
// Set Locale and notify listeners
switchLocale ( Locale ( settings [ " Locale " ] ) ) ;
2021-04-06 20:33:44 +00:00
// Decide whether to enable Experiments
blockUnknownConnections = settings [ " BlockUnknownConnections " ] ;
2021-03-16 19:54:48 +00:00
// Decide whether to enable Experiments
experimentsEnabled = settings [ " ExperimentsEnabled " ] ;
// Set the internal experiments map. Casting from the Map<dynamic, dynamic> that we get from JSON
experiments = new HashMap < String , bool > . from ( settings [ " Experiments " ] ) ;
2021-06-24 07:36:41 +00:00
// single pane vs dual pane preferences
_uiColumnModePortrait = uiColumnModeFromString ( settings [ " UIColumnModePortrait " ] ) ;
_uiColumnModeLandscape = uiColumnModeFromString ( settings [ " UIColumnModeLandscape " ] ) ;
2021-03-16 19:54:48 +00:00
// Push the experimental settings to Consumers of Settings
2021-03-10 17:40:14 +00:00
notifyListeners ( ) ;
}
2021-03-16 19:54:48 +00:00
/// Initialize the Package Version information
2021-03-09 01:23:37 +00:00
initPackageInfo ( ) {
PackageInfo . fromPlatform ( ) . then ( ( PackageInfo newPackageInfo ) {
packageInfo = newPackageInfo ;
notifyListeners ( ) ;
} ) ;
}
2021-04-06 20:33:44 +00:00
/// Switch the Locale of the App
2021-03-09 01:23:37 +00:00
switchLocale ( Locale newLocale ) {
locale = newLocale ;
notifyListeners ( ) ;
}
2021-04-06 20:33:44 +00:00
/// Block Unknown Connections will autoblock connections if they authenticate with public key not in our contacts list.
/// This is one of the best tools we have to combat abuse, while it isn't ideal it does allow a user to curate their contacts
/// list without being bothered by spurious requests (either permanently, or as a short term measure).
/// Note: This is not an *appear offline* setting which would explicitly close the listen port, rather than simply auto disconnecting unknown attempts.
forbidUnknownConnections ( ) {
blockUnknownConnections = true ;
notifyListeners ( ) ;
}
/// Allow Unknown Connections will allow new contact requires from unknown public keys
/// See above for more information.
allowUnknownConnections ( ) {
blockUnknownConnections = false ;
notifyListeners ( ) ;
}
2021-03-16 19:54:48 +00:00
/// Turn Experiments On, this will also have the side effect of enabling any
/// Experiments that have been previously activated.
enableExperiments ( ) {
experimentsEnabled = true ;
notifyListeners ( ) ;
}
/// Turn Experiments Off. This will disable **all** active experiments.
/// Note: This will not set the preference for individual experiments, if experiments are enabled
/// any experiments that were active previously will become active again unless they are explicitly disabled.
disableExperiments ( ) {
experimentsEnabled = false ;
notifyListeners ( ) ;
}
/// Turn on a specific experiment.
enableExperiment ( String key ) {
experiments . update ( key , ( value ) = > true , ifAbsent: ( ) = > true ) ;
2021-05-27 20:28:31 +00:00
notifyListeners ( ) ;
2021-03-16 19:54:48 +00:00
}
/// Turn off a specific experiment
disableExperiment ( String key ) {
experiments . update ( key , ( value ) = > false , ifAbsent: ( ) = > false ) ;
2021-05-27 20:28:31 +00:00
notifyListeners ( ) ;
2021-03-16 19:54:48 +00:00
}
2021-06-24 07:36:41 +00:00
DualpaneMode get uiColumnModePortrait = > _uiColumnModePortrait ;
set uiColumnModePortrait ( DualpaneMode newval ) {
2021-06-24 00:35:33 +00:00
this . _uiColumnModePortrait = newval ;
notifyListeners ( ) ;
}
2021-06-24 07:36:41 +00:00
DualpaneMode get uiColumnModeLandscape = > _uiColumnModeLandscape ;
set uiColumnModeLandscape ( DualpaneMode newval ) {
2021-06-24 00:35:33 +00:00
this . _uiColumnModeLandscape = newval ;
notifyListeners ( ) ;
}
2021-06-24 07:36:41 +00:00
List < int > uiColumns ( bool isLandscape ) {
var m = ( ! isLandscape | | uiColumnModeLandscape = = DualpaneMode . CopyPortrait ) ? uiColumnModePortrait : uiColumnModeLandscape ;
switch ( m ) {
case DualpaneMode . Single: return [ 1 ] ;
case DualpaneMode . Dual1to2: return [ 1 , 2 ] ;
case DualpaneMode . Dual1to4: return [ 1 , 4 ] ;
}
print ( " impossible column configuration: portrait/ $ uiColumnModePortrait landscape/ $ uiColumnModeLandscape " ) ;
return [ 1 ] ;
}
static List < DualpaneMode > uiColumnModeOptions ( bool isLandscape ) {
if ( isLandscape ) return [ DualpaneMode . CopyPortrait , DualpaneMode . Single , DualpaneMode . Dual1to2 , DualpaneMode . Dual1to4 , ] ;
else return [ DualpaneMode . Single , DualpaneMode . Dual1to2 , DualpaneMode . Dual1to4 ] ;
}
static DualpaneMode uiColumnModeFromString ( String m ) {
switch ( m ) {
case " DualpaneMode.Single " : return DualpaneMode . Single ;
case " DualpaneMode.Dual1to2 " : return DualpaneMode . Dual1to2 ;
case " DualpaneMode.Dual1to4 " : return DualpaneMode . Dual1to4 ;
case " DualpaneMode.CopyPortrait " : return DualpaneMode . CopyPortrait ;
}
print ( " Error: ui requested translation of column mode [ $ m ] which doesn't exist " ) ;
return DualpaneMode . Single ;
}
static String uiColumnModeToString ( DualpaneMode m ) {
// todo: translate
switch ( m ) {
case DualpaneMode . Single: return " Single " ;
case DualpaneMode . Dual1to2: return " Double (1:2) " ;
case DualpaneMode . Dual1to4: return " Double (1:4) " ;
case DualpaneMode . CopyPortrait: return " Same as portrait mode setting " ;
}
}
2021-03-16 19:54:48 +00:00
/// Construct a default settings object.
2021-03-10 17:40:14 +00:00
Settings ( this . locale , this . theme ) ;
2021-03-16 19:54:48 +00:00
/// Convert this Settings object to a JSON representation for serialization on the
/// event bus.
2021-03-10 17:40:14 +00:00
dynamic asJson ( ) {
2021-06-19 03:31:25 +00:00
var themeString = theme . identifier ( ) ;
2021-03-10 17:40:14 +00:00
return {
" Locale " : this . locale . languageCode ,
" Theme " : themeString ,
" PreviousPid " : - 1 ,
2021-04-06 20:33:44 +00:00
" BlockUnknownConnections " : blockUnknownConnections ,
2021-03-16 19:54:48 +00:00
" ExperimentsEnabled " : this . experimentsEnabled ,
" Experiments " : experiments ,
2021-03-10 17:40:14 +00:00
" StateRootPane " : 0 ,
2021-06-24 07:36:41 +00:00
" FirstTime " : false ,
" UIColumnModePortrait " : uiColumnModePortrait . toString ( ) ,
" UIColumnModeLandscape " : uiColumnModeLandscape . toString ( ) ,
2021-03-10 17:40:14 +00:00
} ;
}
}