mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-25 14:29:22 +00:00
Can upload new account image
This commit is contained in:
parent
7071600c3f
commit
8feea380a4
38
lib/helpers/settings_helper.dart
Normal file
38
lib/helpers/settings_helper.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:comunic/models/account_image_settings.dart';
|
||||
import 'package:comunic/models/api_request.dart';
|
||||
|
||||
/// Settings helper
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
const _APIAccountImageVisibilityAPILevels = {
|
||||
"open": AccountImageVisibilityLevels.EVERYONE,
|
||||
"public": AccountImageVisibilityLevels.COMUNIC_USERS,
|
||||
"friends": AccountImageVisibilityLevels.FRIENDS_ONLY,
|
||||
};
|
||||
|
||||
class SettingsHelper {
|
||||
/// Get & return account image settings
|
||||
static Future<AccountImageSettings> getAccountImageSettings() async {
|
||||
final response =
|
||||
(await APIRequest(uri: "settings/get_account_image", needLogin: true)
|
||||
.exec())
|
||||
.assertOk()
|
||||
.getObject();
|
||||
|
||||
return AccountImageSettings(
|
||||
hasImage: response["has_image"],
|
||||
imageURL: response["image_url"],
|
||||
visibility:
|
||||
_APIAccountImageVisibilityAPILevels[response["visibility"]]);
|
||||
}
|
||||
|
||||
/// Upload a new account image
|
||||
static Future<bool> uploadAccountImage(File newImage) async =>
|
||||
(await APIRequest(uri: "settings/upload_account_image", needLogin: true)
|
||||
.addFile("picture", newImage)
|
||||
.execWithFiles())
|
||||
.isOK;
|
||||
}
|
21
lib/models/account_image_settings.dart
Normal file
21
lib/models/account_image_settings.dart
Normal file
@ -0,0 +1,21 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// Account image settings
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
enum AccountImageVisibilityLevels { EVERYONE, COMUNIC_USERS, FRIENDS_ONLY }
|
||||
|
||||
class AccountImageSettings {
|
||||
final bool hasImage;
|
||||
final String imageURL;
|
||||
final AccountImageVisibilityLevels visibility;
|
||||
|
||||
const AccountImageSettings({
|
||||
@required this.hasImage,
|
||||
@required this.imageURL,
|
||||
@required this.visibility,
|
||||
}) : assert(hasImage != null),
|
||||
assert(imageURL != null),
|
||||
assert(visibility != null);
|
||||
}
|
@ -22,14 +22,25 @@ class APIRequest {
|
||||
if (this.args == null) this.args = Map();
|
||||
}
|
||||
|
||||
void addString(String name, String value) => args[name] = value;
|
||||
APIRequest addString(String name, String value) {
|
||||
args[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
void addInt(String name, int value) => args[name] = value.toString();
|
||||
APIRequest addInt(String name, int value) {
|
||||
args[name] = value.toString();
|
||||
return this;
|
||||
}
|
||||
|
||||
void addBool(String name, bool value) =>
|
||||
args[name] = value ? "true" : "false";
|
||||
APIRequest addBool(String name, bool value) {
|
||||
args[name] = value ? "true" : "false";
|
||||
return this;
|
||||
}
|
||||
|
||||
void addFile(String name, File file) => files[name] = file;
|
||||
APIRequest addFile(String name, File file) {
|
||||
files[name] = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
void addArgs(Map<String, String> newArgs) => args.addAll(newArgs);
|
||||
|
||||
|
@ -1,11 +1,18 @@
|
||||
import 'package:comunic/helpers/settings_helper.dart';
|
||||
import 'package:comunic/models/account_image_settings.dart';
|
||||
import 'package:comunic/ui/widgets/async_screen_widget.dart';
|
||||
import 'package:comunic/ui/widgets/network_image_widget.dart';
|
||||
import 'package:comunic/utils/files_utils.dart';
|
||||
import 'package:comunic/utils/intl_utils.dart';
|
||||
import 'package:comunic/utils/ui_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:settings_ui/settings_ui.dart';
|
||||
|
||||
/// Account image settings section
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class AccountImageSettings extends StatelessWidget {
|
||||
class AccountImageSettingsScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -17,15 +24,75 @@ class AccountImageSettings extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _AccountImageSettingsBody extends StatefulWidget {
|
||||
@override
|
||||
__AccountImageSettingsBodyState createState() => __AccountImageSettingsBodyState();
|
||||
__AccountImageSettingsBodyState createState() =>
|
||||
__AccountImageSettingsBodyState();
|
||||
}
|
||||
|
||||
class __AccountImageSettingsBodyState extends State<_AccountImageSettingsBody> {
|
||||
AccountImageSettings _settings;
|
||||
|
||||
final _key = GlobalKey<AsyncScreenWidgetState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
return AsyncScreenWidget(
|
||||
key: _key,
|
||||
onReload: () async =>
|
||||
_settings = await SettingsHelper.getAccountImageSettings(),
|
||||
onBuild: () => _buildLayout(),
|
||||
errorMessage: tr("Could not get account image settings!"),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLayout() {
|
||||
return SettingsList(
|
||||
sections: [
|
||||
SettingsSection(
|
||||
title: tr("General"),
|
||||
tiles: _settings.hasImage
|
||||
? _buildHasAccountImageTiles()
|
||||
: _buildNoAccountImageTiles(),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// When user has no account image yet
|
||||
List<SettingsTile> _buildNoAccountImageTiles() {}
|
||||
|
||||
/// When the user has an account image
|
||||
List<SettingsTile> _buildHasAccountImageTiles() {
|
||||
return [
|
||||
// Current account image (if any)
|
||||
SettingsTile(
|
||||
title: tr("Current account image"),
|
||||
leading: NetworkImageWidget(
|
||||
url: _settings.imageURL,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
SettingsTile(
|
||||
title: tr("Upload new account image"),
|
||||
onTap: () => _uploadAccountImage(),
|
||||
),
|
||||
SettingsTile(title: tr("Change account image visibility")),
|
||||
SettingsTile(title: tr("Delete account image"))
|
||||
];
|
||||
}
|
||||
|
||||
/// Upload a new account image
|
||||
void _uploadAccountImage() async {
|
||||
final image = await pickImage(context);
|
||||
|
||||
if (image == null) return;
|
||||
|
||||
if (!await SettingsHelper.uploadAccountImage(image)) {
|
||||
showSimpleSnack(context, tr("Could not upload your account image!"));
|
||||
return;
|
||||
}
|
||||
|
||||
_key.currentState.refresh();
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class __AccountSettingsBodyState extends State<_AccountSettingsBody> {
|
||||
title: tr("Account image"),
|
||||
subtitle: tr("Customize your account image"),
|
||||
leading: Icon(Icons.account_circle),
|
||||
onTap: () => _openSection(AccountImageSettings()),
|
||||
onTap: () => _openSection(AccountImageSettingsScreen()),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
96
lib/ui/widgets/async_screen_widget.dart
Normal file
96
lib/ui/widgets/async_screen_widget.dart
Normal file
@ -0,0 +1,96 @@
|
||||
import 'package:comunic/ui/widgets/safe_state.dart';
|
||||
import 'package:comunic/utils/intl_utils.dart';
|
||||
import 'package:comunic/utils/ui_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Widget that can be used to easily implement fetch of remote ressources
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class AsyncScreenWidget extends StatefulWidget {
|
||||
/// Reload function
|
||||
///
|
||||
/// Can be an asynchronous function that takes no arguments and throw an
|
||||
/// [Exception] in case of failure
|
||||
///
|
||||
/// You do not need to call [State.setState] on this function, it is
|
||||
/// automatically done by this widget
|
||||
final Future<void> Function() onReload;
|
||||
|
||||
/// Build function
|
||||
///
|
||||
/// This function will be called whenever [isReady] becomes true
|
||||
final Widget Function() onBuild;
|
||||
|
||||
/// Error message that will be shown in case of error
|
||||
final String errorMessage;
|
||||
|
||||
const AsyncScreenWidget({
|
||||
Key key,
|
||||
@required this.onReload,
|
||||
@required this.onBuild,
|
||||
@required this.errorMessage,
|
||||
}) : assert(onReload != null),
|
||||
assert(onBuild != null),
|
||||
assert(errorMessage != null),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
AsyncScreenWidgetState createState() => AsyncScreenWidgetState();
|
||||
}
|
||||
|
||||
class AsyncScreenWidgetState extends SafeState<AsyncScreenWidget> {
|
||||
bool error = false;
|
||||
bool ready = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
refresh();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// In case of error
|
||||
if (error)
|
||||
return buildErrorCard(widget.errorMessage, actions: [
|
||||
MaterialButton(
|
||||
onPressed: () => refresh(),
|
||||
child: Text(tr("Try again").toUpperCase()),
|
||||
)
|
||||
]);
|
||||
|
||||
// Show loading states
|
||||
if (!ready) return buildCenteredProgressBar();
|
||||
|
||||
// The widget is ready, show it
|
||||
return RefreshIndicator(
|
||||
child: widget.onBuild(),
|
||||
onRefresh: () => refresh(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Refresh this screen
|
||||
Future<void> refresh() async {
|
||||
try {
|
||||
setState(() {
|
||||
error = false;
|
||||
ready = false;
|
||||
});
|
||||
|
||||
// Call parent method
|
||||
await widget.onReload();
|
||||
|
||||
setState(() {
|
||||
ready = true;
|
||||
});
|
||||
} catch (e, stack) {
|
||||
print(e);
|
||||
print(stack);
|
||||
|
||||
setState(() {
|
||||
error = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user