Unlock Profiles #4
|
@ -0,0 +1,12 @@
|
|||
# State Management
|
||||
|
||||
We use a MultiProvider to distribute state to the underlying widgets. Right now there are 2 top
|
||||
level Providers: FlwtchState (the app) and OpaqueTheme.
|
||||
|
||||
## Theme
|
||||
|
||||
OpaqueTheme extends ChangeProvider. SetLight and SetDark are functions that call notifyListeners()
|
||||
|
||||
ChangeNotiferProvider is used to package OpaqueTheme into a provider which is a top level
|
||||
provider (as every widget in the app needs to be re-rendered on a theme switch).
|
||||
|
|
@ -71,11 +71,11 @@ class MainActivity: FlutterActivity() {
|
|||
Log.i("MainActivity.kt", "got event chan: " + eventbus_chan + " launching corouting...")
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
while(true) {
|
||||
val jsonEvent = Cwtch.getAppBusEvent()
|
||||
Log.i("MainActivity.kt", "got appbusEvent: " + jsonEvent)
|
||||
launch(Dispatchers.Main) {
|
||||
eventbus_chan.invokeMethod("AppbusEvent", jsonEvent)
|
||||
}
|
||||
//val jsonEvent = Cwtch.getAppBusEvent()
|
||||
// Log.i("MainActivity.kt", "got appbusEvent: " + jsonEvent)
|
||||
// launch(Dispatchers.Main) {
|
||||
// //eventbus_chan.invokeMethod("AppbusEvent", jsonEvent)
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,12 @@ class MainActivity: FlutterActivity() {
|
|||
val pass = (call.argument("pass") as? String) ?: "";
|
||||
Cwtch.createProfile(nick, pass)
|
||||
}
|
||||
"LoadProfiles" -> {
|
||||
val pass = (call.argument("pass") as? String) ?: "";
|
||||
Cwtch.loadProfiles(pass)
|
||||
}
|
||||
"GetProfiles" -> result.success(Cwtch.getProfiles())
|
||||
"ACNEvents" -> result.success(Cwtch.acnEvents())
|
||||
// "ACNEvents" -> result.success(Cwtch.acnEvents())
|
||||
"ContactEvents" -> result.success(Cwtch.contactEvents())
|
||||
"GetContacts" -> {
|
||||
val onion = (call.argument("profile") as? String) ?: "";
|
||||
|
|
|
@ -3,6 +3,7 @@ abstract class Cwtch {
|
|||
|
||||
void SelectProfile(String onion);
|
||||
void CreateProfile(String nick, String pass);
|
||||
void LoadProfiles(String pass);
|
||||
|
||||
Future<String> ACNEvents();
|
||||
Future<String> ContactEvents();
|
||||
|
|
|
@ -18,6 +18,9 @@ typedef VoidFromStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>
|
|||
typedef access_cwtch_eventbus_function = Void Function();
|
||||
typedef NextEventFn = void Function();
|
||||
|
||||
typedef string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length);
|
||||
typedef StringFn = void Function(Pointer<Utf8> dir, int);
|
||||
|
||||
typedef get_json_blob_void_function = Pointer<Utf8> Function();
|
||||
typedef GetJsonBlobVoidFn = Pointer<Utf8> Function();
|
||||
|
||||
|
@ -80,6 +83,14 @@ class CwtchFfi implements Cwtch {
|
|||
CreateProfile(Utf8.toUtf8(nick), nick.length, Utf8.toUtf8(pass), pass.length);
|
||||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void LoadProfiles(String pass) {
|
||||
var loadProfileC = library.lookup<NativeFunction<string_to_void_function>>("c_LoadProfiles");
|
||||
// ignore: non_constant_identifier_names
|
||||
final LoadProfiles = loadProfileC.asFunction<StringFn>();
|
||||
LoadProfiles(Utf8.toUtf8(pass), pass.length);
|
||||
}
|
||||
|
||||
Future<String> ACNEvents() async {
|
||||
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
|
||||
"c_ACNEvents");
|
||||
|
|
|
@ -32,8 +32,8 @@ class CwtchGomobile implements Cwtch {
|
|||
androidHomeDirectory = getApplicationDocumentsDirectory();
|
||||
androidLibraryDir = appInfoPlatform.invokeMethod('getNativeLibDir');
|
||||
|
||||
final appbusEventChannel = MethodChannel(appbusEventChannelName);
|
||||
appbusEventChannel.setMethodCallHandler(this._handleAppbusEvent);
|
||||
// final appbusEventChannel = MethodChannel(appbusEventChannelName);
|
||||
// appbusEventChannel.setMethodCallHandler(this._handleAppbusEvent);
|
||||
}
|
||||
|
||||
Future<void> Start() async {
|
||||
|
@ -57,6 +57,10 @@ class CwtchGomobile implements Cwtch {
|
|||
cwtchPlatform.invokeMethod("CreateProfile", {"nick": nick, "pass": pass});
|
||||
}
|
||||
|
||||
void LoadProfiles(String pass) {
|
||||
cwtchPlatform.invokeMethod("LoadProfiles", {"pass": pass});
|
||||
}
|
||||
|
||||
Future<String> ACNEvents() {
|
||||
return cwtchPlatform.invokeMethod("ACNEvents");
|
||||
}
|
||||
|
@ -87,5 +91,4 @@ class CwtchGomobile implements Cwtch {
|
|||
return cwtchPlatform.invokeMethod("GetMessage", {"profile" : profile, "contact": handle, "start": start, "end": end});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -32,17 +32,17 @@ class FlwtchState extends State<Flwtch> {
|
|||
// mergenotes: ui stuff
|
||||
ProfileModel selectedProfile;
|
||||
String selectedConversation = "";
|
||||
var columns = [1];// default or 'single column' mode
|
||||
var columns = [1]; // default or 'single column' mode
|
||||
//var columns = [1, 1, 2];
|
||||
|
||||
AppModel appStatus;
|
||||
HashMap<String, ProfileModel> profiles;
|
||||
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
cwtchInit = false;
|
||||
|
||||
profiles = new HashMap<String, ProfileModel>();
|
||||
|
||||
print("FlwtchState.initState()");
|
||||
|
@ -80,32 +80,55 @@ class FlwtchState extends State<Flwtch> {
|
|||
});
|
||||
}
|
||||
|
||||
ChangeNotifierProvider<OpaqueTheme> getOpaqueProvider() {
|
||||
return ChangeNotifierProvider(create: (context) => OpaqueTheme(Opaque.dark));
|
||||
}
|
||||
|
||||
Provider<FlwtchState> getFlwtchStateProvider() {
|
||||
return Provider<FlwtchState>(
|
||||
create: (_) => this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
appStatus = AppModel(cwtch: cwtch);
|
||||
|
||||
final newTextTheme = Theme.of(context).textTheme.apply(
|
||||
bodyColor: Opaque.current().mainTextColor(),
|
||||
displayColor: Opaque.current().mainTextColor(),
|
||||
);
|
||||
bodyColor: Opaque.current().mainTextColor(),
|
||||
displayColor: Opaque.current().mainTextColor(),
|
||||
);
|
||||
|
||||
print("FlwtchState.build() cwtchInit: $cwtchInit");
|
||||
return Provider<FlwtchState>(
|
||||
create: (_) => this,
|
||||
child: MaterialApp(
|
||||
title: 'Cwtch',
|
||||
theme: ThemeData(
|
||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
primarySwatch: Colors.red,
|
||||
primaryColor: Opaque.current().backgroundMainColor(),
|
||||
canvasColor: Opaque.current().backgroundPaneColor(),
|
||||
accentColor: Opaque.current().defaultButtonColor(),
|
||||
buttonColor: Opaque.current().defaultButtonColor(),
|
||||
textTheme: newTextTheme,
|
||||
),
|
||||
// from dan: home: cwtchInit == true ? ProfileMgrView(cwtch) : SplashView(),
|
||||
// from erinn: home: columns.length == 3 ? TripleColumnView() : ProfileMgrView(),
|
||||
home: cwtchInit == true ? (columns.length == 3 ? TripleColumnView() : ProfileMgrView()) : SplashView(),
|
||||
));
|
||||
return MultiProvider(
|
||||
providers: [getFlwtchStateProvider(), getOpaqueProvider()],
|
||||
builder: (context, widget) { return MaterialApp(
|
||||
title: 'Cwtch',
|
||||
theme: ThemeData(
|
||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
primarySwatch: Colors.red,
|
||||
primaryColor: Provider.of<OpaqueTheme>(context)
|
||||
.current()
|
||||
.backgroundMainColor(),
|
||||
canvasColor: Provider.of<OpaqueTheme>(context)
|
||||
.current()
|
||||
.backgroundPaneColor(),
|
||||
accentColor: Provider.of<OpaqueTheme>(context)
|
||||
.current()
|
||||
.defaultButtonColor(),
|
||||
buttonColor: Provider.of<OpaqueTheme>(context)
|
||||
.current()
|
||||
.defaultButtonColor(),
|
||||
textTheme: newTextTheme,
|
||||
),
|
||||
// from dan: home: cwtchInit == true ? ProfileMgrView(cwtch) : SplashView(),
|
||||
// from erinn: home: columns.length == 3 ? TripleColumnView() : ProfileMgrView(),
|
||||
home: cwtchInit == true
|
||||
? (columns.length == 3
|
||||
? TripleColumnView()
|
||||
: ProfileMgrView())
|
||||
: SplashView(),
|
||||
);},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
import 'dart:ui';
|
||||
import 'dart:core';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
abstract class OpaqueThemeType {
|
||||
static final Color red = Color(0xFFFF0000);
|
||||
Color backgroundMainColor(){return red;}
|
||||
|
@ -421,9 +423,12 @@ class Opaque extends OpaqueThemeType {
|
|||
int chatPaneMinSize() { return chatPaneMinSizeBase[p[scale]]; }
|
||||
int doublePaneMinSize() { return sidePaneMinSize() + chatPaneMinSize(); }
|
||||
|
||||
static OpaqueThemeType _current;
|
||||
static final OpaqueThemeType dark = CwtchDark();
|
||||
static final OpaqueThemeType light = CwtchLight();
|
||||
static OpaqueThemeType current() { return dark; }
|
||||
static void setDark() { _current = dark; }
|
||||
static void setLight() { _current = light; }
|
||||
static OpaqueThemeType current() { if (_current == null) {setDark();} return _current; }
|
||||
|
||||
|
||||
int scale = 2;
|
||||
|
@ -507,3 +512,15 @@ int scale = 2;
|
|||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// TODO: Wire into libCwtch saveSettings / updateTheme etc...
|
||||
class OpaqueTheme extends ChangeNotifier {
|
||||
OpaqueThemeType theme;
|
||||
void setDark() { theme = Opaque.dark; notifyListeners();}
|
||||
void setLight() { theme = Opaque.light; notifyListeners();}
|
||||
OpaqueThemeType current() { return theme; }
|
||||
|
||||
OpaqueTheme(this.theme);
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/main.dart';
|
||||
import 'package:flutter_app/opaque.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class GlobalSettingsView extends StatefulWidget {
|
||||
@override
|
||||
|
@ -35,7 +38,18 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
},
|
||||
),
|
||||
Text("Zoom"),
|
||||
Text("Theme"),
|
||||
SwitchListTile(
|
||||
title: const Text('Theme'),
|
||||
value: Provider.of<OpaqueTheme>(context).current() == Opaque.light,
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
Provider.of<OpaqueTheme>(context, listen: false).setLight();
|
||||
} else {
|
||||
Provider.of<OpaqueTheme>(context, listen: false).setDark();
|
||||
}
|
||||
},
|
||||
secondary: const Icon(Icons.lightbulb_outline),
|
||||
),
|
||||
Text("Experiments enabled"),
|
||||
Text("Text magnification reference"),
|
||||
Text("Acknowledgements"),
|
||||
|
|
|
@ -19,7 +19,6 @@ class ProfileMgrView extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||
HashMap<String, ProfileModel> _profiles;
|
||||
final ctrlrPassword = TextEditingController();
|
||||
|
||||
@override
|
||||
|
@ -30,24 +29,6 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_profiles == null) {
|
||||
_profiles = new HashMap<String, ProfileModel>();
|
||||
}
|
||||
|
||||
if (_profiles.length < 1) {
|
||||
Provider.of<FlwtchState>(context).cwtch.GetProfiles().then((profilesJson) {
|
||||
jsonDecode(profilesJson).forEach((profile) {
|
||||
ProfileModel profile1 = new ProfileModel();
|
||||
profile1.onion = profile['onion'];
|
||||
profile1.nickname = profile['name'];
|
||||
profile1.creationDate = "4 jan 2020";
|
||||
profile1.contacts = new HashMap<String, ContactModel>();
|
||||
profile1.imagePath = profile['imagePath'];
|
||||
|
||||
_profiles.putIfAbsent(profile1.onion, () => profile1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return Scaffold (
|
||||
appBar: AppBar(
|
||||
|
@ -129,7 +110,12 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
ElevatedButton(
|
||||
child: const Text('Unlock'),
|
||||
onPressed: () {
|
||||
setState(() => _profiles.clear());
|
||||
Provider
|
||||
.of<FlwtchState>(context, listen: false)
|
||||
.cwtch
|
||||
.LoadProfiles(ctrlrPassword.value.text);
|
||||
Provider.of<FlwtchState>(context, listen: false)
|
||||
.loadProfiles();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue