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();
|
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) =>
|
APIRequest addBool(String name, bool value) {
|
||||||
args[name] = value ? "true" : "false";
|
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);
|
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/intl_utils.dart';
|
||||||
|
import 'package:comunic/utils/ui_utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:settings_ui/settings_ui.dart';
|
||||||
|
|
||||||
/// Account image settings section
|
/// Account image settings section
|
||||||
///
|
///
|
||||||
/// @author Pierre Hubert
|
/// @author Pierre Hubert
|
||||||
|
|
||||||
class AccountImageSettings extends StatelessWidget {
|
class AccountImageSettingsScreen extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -17,15 +24,75 @@ class AccountImageSettings extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _AccountImageSettingsBody extends StatefulWidget {
|
class _AccountImageSettingsBody extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
__AccountImageSettingsBodyState createState() => __AccountImageSettingsBodyState();
|
__AccountImageSettingsBodyState createState() =>
|
||||||
|
__AccountImageSettingsBodyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class __AccountImageSettingsBodyState extends State<_AccountImageSettingsBody> {
|
class __AccountImageSettingsBodyState extends State<_AccountImageSettingsBody> {
|
||||||
|
AccountImageSettings _settings;
|
||||||
|
|
||||||
|
final _key = GlobalKey<AsyncScreenWidgetState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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"),
|
title: tr("Account image"),
|
||||||
subtitle: tr("Customize your account image"),
|
subtitle: tr("Customize your account image"),
|
||||||
leading: Icon(Icons.account_circle),
|
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