mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 11:18:41 +00:00
fix #87
This commit is contained in:
parent
f485366719
commit
6abfecb4f3
5 changed files with 248 additions and 217 deletions
|
|
@ -107,10 +107,13 @@ class UserCheckbox extends StatelessWidget {
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
|
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
color: Theme.of(context).colorScheme.outline.withAlpha(50),
|
||||||
color: Theme.of(context).colorScheme.outline,
|
boxShadow: [
|
||||||
width: 1.0,
|
BoxShadow(
|
||||||
),
|
blurRadius: 10.9,
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.1),
|
||||||
|
),
|
||||||
|
],
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
@ -157,6 +160,15 @@ class UserCheckbox extends StatelessWidget {
|
||||||
Expanded(child: Container()),
|
Expanded(child: Container()),
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: isChecked,
|
value: isChecked,
|
||||||
|
side: WidgetStateBorderSide.resolveWith(
|
||||||
|
(Set states) {
|
||||||
|
if (states.contains(WidgetState.selected)) {
|
||||||
|
return BorderSide(width: 0);
|
||||||
|
}
|
||||||
|
return BorderSide(
|
||||||
|
width: 1, color: Theme.of(context).colorScheme.outline);
|
||||||
|
},
|
||||||
|
),
|
||||||
onChanged: (bool? value) {
|
onChanged: (bool? value) {
|
||||||
onChanged(user.userId, value ?? false);
|
onChanged(user.userId, value ?? false);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -157,45 +157,47 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.lang.shareImageTitle),
|
title: Text(context.lang.shareImageTitle),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: SafeArea(
|
||||||
padding: EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10),
|
child: Padding(
|
||||||
child: Column(
|
padding: EdgeInsets.only(bottom: 40, left: 10, top: 20, right: 10),
|
||||||
children: [
|
child: Column(
|
||||||
Padding(
|
children: [
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
Padding(
|
||||||
child: TextField(
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
onChanged: _filterUsers,
|
child: TextField(
|
||||||
decoration: getInputDecoration(
|
onChanged: _filterUsers,
|
||||||
context, context.lang.searchUsernameInput),
|
decoration: getInputDecoration(
|
||||||
|
context, context.lang.searchUsernameInput),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (showRealTwonlyWarning) const SizedBox(height: 10),
|
||||||
if (showRealTwonlyWarning) const SizedBox(height: 10),
|
if (showRealTwonlyWarning)
|
||||||
if (showRealTwonlyWarning)
|
Text(
|
||||||
Text(
|
context.lang.shareImageAllTwonlyWarning,
|
||||||
context.lang.shareImageAllTwonlyWarning,
|
style: TextStyle(color: Colors.orange),
|
||||||
style: TextStyle(color: Colors.orange),
|
),
|
||||||
),
|
const SizedBox(height: 10),
|
||||||
const SizedBox(height: 10),
|
BestFriendsSelector(
|
||||||
BestFriendsSelector(
|
users: _bestFriends,
|
||||||
users: _bestFriends,
|
|
||||||
selectedUserIds: _selectedUserIds,
|
|
||||||
maxTotalMediaCounter: maxTotalMediaCounter,
|
|
||||||
isRealTwonly: widget.isRealTwonly,
|
|
||||||
updateStatus: updateStatus,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
if (_otherUsers.isNotEmpty)
|
|
||||||
HeadLineComponent(context.lang.shareImageAllUsers),
|
|
||||||
Expanded(
|
|
||||||
child: UserList(
|
|
||||||
List.from(_otherUsers),
|
|
||||||
maxTotalMediaCounter,
|
|
||||||
selectedUserIds: _selectedUserIds,
|
selectedUserIds: _selectedUserIds,
|
||||||
|
maxTotalMediaCounter: maxTotalMediaCounter,
|
||||||
isRealTwonly: widget.isRealTwonly,
|
isRealTwonly: widget.isRealTwonly,
|
||||||
updateStatus: updateStatus,
|
updateStatus: updateStatus,
|
||||||
),
|
),
|
||||||
)
|
const SizedBox(height: 10),
|
||||||
],
|
if (_otherUsers.isNotEmpty)
|
||||||
|
HeadLineComponent(context.lang.shareImageAllUsers),
|
||||||
|
Expanded(
|
||||||
|
child: UserList(
|
||||||
|
List.from(_otherUsers),
|
||||||
|
maxTotalMediaCounter,
|
||||||
|
selectedUserIds: _selectedUserIds,
|
||||||
|
isRealTwonly: widget.isRealTwonly,
|
||||||
|
updateStatus: updateStatus,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: SizedBox(
|
floatingActionButton: SizedBox(
|
||||||
|
|
@ -274,8 +276,8 @@ class UserList extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Step 1: Sort the users alphabetically
|
// Step 1: Sort the users alphabetically
|
||||||
users.sort(
|
users
|
||||||
(a, b) => getContactDisplayName(a).compareTo(getContactDisplayName(b)));
|
.sort((a, b) => a.lastMessageExchange.compareTo(b.lastMessageExchange));
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
restorationId: 'new_message_users_list',
|
restorationId: 'new_message_users_list',
|
||||||
|
|
@ -309,6 +311,15 @@ class UserList extends StatelessWidget {
|
||||||
),
|
),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
value: selectedUserIds.contains(user.userId),
|
value: selectedUserIds.contains(user.userId),
|
||||||
|
side: WidgetStateBorderSide.resolveWith(
|
||||||
|
(Set states) {
|
||||||
|
if (states.contains(WidgetState.selected)) {
|
||||||
|
return BorderSide(width: 0);
|
||||||
|
}
|
||||||
|
return BorderSide(
|
||||||
|
width: 1, color: Theme.of(context).colorScheme.outline);
|
||||||
|
},
|
||||||
|
),
|
||||||
onChanged: (bool? value) {
|
onChanged: (bool? value) {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
updateStatus(user.userId, value);
|
updateStatus(user.userId, value);
|
||||||
|
|
|
||||||
|
|
@ -251,92 +251,96 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: SafeArea(
|
||||||
children: [
|
child: Column(
|
||||||
Expanded(
|
children: [
|
||||||
child: ListView.builder(
|
Expanded(
|
||||||
itemCount: messages.length, // Number of items in the list
|
child: ListView.builder(
|
||||||
reverse: true,
|
itemCount: messages.length, // Number of items in the list
|
||||||
itemBuilder: (context, i) {
|
reverse: true,
|
||||||
bool lastMessageFromSameUser = false;
|
itemBuilder: (context, i) {
|
||||||
if (i > 0) {
|
bool lastMessageFromSameUser = false;
|
||||||
lastMessageFromSameUser =
|
if (i > 0) {
|
||||||
(messages[i - 1].messageOtherId == null &&
|
lastMessageFromSameUser =
|
||||||
messages[i].messageOtherId == null) ||
|
(messages[i - 1].messageOtherId == null &&
|
||||||
(messages[i - 1].messageOtherId != null &&
|
messages[i].messageOtherId == null) ||
|
||||||
messages[i].messageOtherId != null);
|
(messages[i - 1].messageOtherId != null &&
|
||||||
}
|
messages[i].messageOtherId != null);
|
||||||
return ChatListEntry(
|
}
|
||||||
messages[i],
|
return ChatListEntry(
|
||||||
widget.userid,
|
messages[i],
|
||||||
lastMessageFromSameUser,
|
widget.userid,
|
||||||
);
|
lastMessageFromSameUser,
|
||||||
},
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(
|
||||||
padding:
|
bottom: 30, left: 20, right: 20, top: 10),
|
||||||
const EdgeInsets.only(bottom: 30, left: 20, right: 20, top: 10),
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
Expanded(
|
||||||
Expanded(
|
child: TextField(
|
||||||
child: TextField(
|
controller: newMessageController,
|
||||||
controller: newMessageController,
|
onChanged: (value) {
|
||||||
onChanged: (value) {
|
currentInputText = value;
|
||||||
currentInputText = value;
|
setState(() {});
|
||||||
setState(() {});
|
},
|
||||||
},
|
onSubmitted: (_) {
|
||||||
onSubmitted: (_) {
|
_sendMessage();
|
||||||
_sendMessage();
|
},
|
||||||
},
|
decoration: InputDecoration(
|
||||||
decoration: InputDecoration(
|
hintText: context.lang.chatListDetailInput,
|
||||||
hintText: context.lang.chatListDetailInput,
|
contentPadding:
|
||||||
contentPadding:
|
EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
border: OutlineInputBorder(
|
||||||
border: OutlineInputBorder(
|
borderRadius: BorderRadius.circular(
|
||||||
borderRadius: BorderRadius.circular(
|
20), // Set the border radius here
|
||||||
20), // Set the border radius here
|
borderSide: BorderSide(
|
||||||
borderSide: BorderSide(
|
color: Theme.of(context).colorScheme.primary,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
width: 2.0), // Customize border color and width
|
||||||
width: 2.0), // Customize border color and width
|
),
|
||||||
),
|
focusedBorder: OutlineInputBorder(
|
||||||
focusedBorder: OutlineInputBorder(
|
borderRadius: BorderRadius.circular(
|
||||||
borderRadius: BorderRadius.circular(
|
20.0), // Same radius for focused border
|
||||||
20.0), // Same radius for focused border
|
borderSide: BorderSide(
|
||||||
borderSide: BorderSide(
|
color: Theme.of(context).colorScheme.primary,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
width: 2.0),
|
||||||
width: 2.0),
|
),
|
||||||
),
|
enabledBorder: OutlineInputBorder(
|
||||||
enabledBorder: OutlineInputBorder(
|
borderRadius: BorderRadius.circular(
|
||||||
borderRadius: BorderRadius.circular(
|
20.0), // Same radius for enabled border
|
||||||
20.0), // Same radius for enabled border
|
borderSide:
|
||||||
borderSide: BorderSide(color: Colors.grey, width: 2.0),
|
BorderSide(color: Colors.grey, width: 2.0),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(width: 8),
|
||||||
SizedBox(width: 8),
|
(currentInputText != "")
|
||||||
(currentInputText != "")
|
? IconButton(
|
||||||
? IconButton(
|
icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
|
onPressed: () {
|
||||||
onPressed: () {
|
_sendMessage();
|
||||||
_sendMessage();
|
},
|
||||||
},
|
)
|
||||||
)
|
: IconButton(
|
||||||
: IconButton(
|
icon: FaIcon(FontAwesomeIcons.camera),
|
||||||
icon: FaIcon(FontAwesomeIcons.camera),
|
onPressed: () {
|
||||||
onPressed: () {
|
context
|
||||||
context
|
.read<SendNextMediaTo>()
|
||||||
.read<SendNextMediaTo>()
|
.updateSendNextMediaTo(widget.userid);
|
||||||
.updateSendNextMediaTo(widget.userid);
|
globalUpdateOfHomeViewPageIndex(0);
|
||||||
globalUpdateOfHomeViewPageIndex(0);
|
Navigator.popUntil(
|
||||||
Navigator.popUntil(context, (route) => route.isFirst);
|
context, (route) => route.isFirst);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,49 +106,51 @@ class _SearchUsernameView extends State<SearchUsernameView> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.lang.searchUsernameTitle),
|
title: Text(context.lang.searchUsernameTitle),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: SafeArea(
|
||||||
padding: EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10),
|
child: Padding(
|
||||||
child: Column(
|
padding: EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10),
|
||||||
children: [
|
child: Column(
|
||||||
Padding(
|
children: [
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
Padding(
|
||||||
child: TextField(
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
onSubmitted: (_) {
|
child: TextField(
|
||||||
_addNewUser(context);
|
onSubmitted: (_) {
|
||||||
|
_addNewUser(context);
|
||||||
|
},
|
||||||
|
controller: searchUserName,
|
||||||
|
decoration:
|
||||||
|
getInputDecoration(context.lang.searchUsernameInput),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
OutlinedButton.icon(
|
||||||
|
icon: Icon(Icons.qr_code),
|
||||||
|
onPressed: () {
|
||||||
|
showAlertDialog(context, "Coming soon",
|
||||||
|
"This feature is not yet implemented!");
|
||||||
},
|
},
|
||||||
controller: searchUserName,
|
label: Text(context.lang.searchUsernameQrCodeBtn),
|
||||||
decoration:
|
|
||||||
getInputDecoration(context.lang.searchUsernameInput),
|
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 30),
|
||||||
const SizedBox(height: 20),
|
if (hasRequestedUsers)
|
||||||
OutlinedButton.icon(
|
HeadLineComponent(
|
||||||
icon: Icon(Icons.qr_code),
|
context.lang.searchUsernameNewFollowerTitle,
|
||||||
onPressed: () {
|
),
|
||||||
showAlertDialog(context, "Coming soon",
|
StreamBuilder(
|
||||||
"This feature is not yet implemented!");
|
stream: contacts,
|
||||||
},
|
builder: (context, snapshot) {
|
||||||
label: Text(context.lang.searchUsernameQrCodeBtn),
|
if (!snapshot.hasData ||
|
||||||
),
|
snapshot.data == null ||
|
||||||
SizedBox(height: 30),
|
snapshot.data!.isEmpty) {
|
||||||
if (hasRequestedUsers)
|
hasRequestedUsers = false;
|
||||||
HeadLineComponent(
|
return Container();
|
||||||
context.lang.searchUsernameNewFollowerTitle,
|
}
|
||||||
),
|
hasRequestedUsers = true;
|
||||||
StreamBuilder(
|
return Expanded(child: ContactsListView(snapshot.data!));
|
||||||
stream: contacts,
|
},
|
||||||
builder: (context, snapshot) {
|
)
|
||||||
if (!snapshot.hasData ||
|
],
|
||||||
snapshot.data == null ||
|
),
|
||||||
snapshot.data!.isEmpty) {
|
|
||||||
hasRequestedUsers = false;
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
hasRequestedUsers = true;
|
|
||||||
return Expanded(child: ContactsListView(snapshot.data!));
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: Padding(
|
floatingActionButton: Padding(
|
||||||
|
|
|
||||||
|
|
@ -9,67 +9,69 @@ class DiagnosticsView extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder<String>(
|
return SafeArea(
|
||||||
future: _loadLogFile(),
|
child: FutureBuilder<String>(
|
||||||
builder: (context, snapshot) {
|
future: _loadLogFile(),
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
builder: (context, snapshot) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
} else if (snapshot.hasError) {
|
return const Center(child: CircularProgressIndicator());
|
||||||
return Center(child: Text('Error: ${snapshot.error}'));
|
} else if (snapshot.hasError) {
|
||||||
} else {
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
final logText = snapshot.data ?? '';
|
} else {
|
||||||
|
final logText = snapshot.data ?? '';
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Diagnostics')),
|
appBar: AppBar(title: const Text('Diagnostics')),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(logText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(logText),
|
child: Row(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
),
|
children: [
|
||||||
Padding(
|
TextButton(
|
||||||
padding: const EdgeInsets.all(16.0),
|
onPressed: () {
|
||||||
child: Row(
|
Clipboard.setData(ClipboardData(text: logText));
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Clipboard.setData(ClipboardData(text: logText));
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Log copied to clipboard!')),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: const Text('Copy All Text'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () async {
|
|
||||||
if (await deleteLogFile()) {
|
|
||||||
if (!context.mounted) return;
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Log file deleted!')),
|
content: Text('Log copied to clipboard!')),
|
||||||
);
|
);
|
||||||
} else {
|
},
|
||||||
if (!context.mounted) return;
|
child: const Text('Copy All Text'),
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
),
|
||||||
const SnackBar(
|
TextButton(
|
||||||
content: Text('Log file does not exist.')),
|
onPressed: () async {
|
||||||
);
|
if (await deleteLogFile()) {
|
||||||
}
|
if (!context.mounted) return;
|
||||||
},
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
child: const Text('Delete Log File'),
|
const SnackBar(
|
||||||
),
|
content: Text('Log file deleted!')),
|
||||||
],
|
);
|
||||||
|
} else {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Log file does not exist.')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('Delete Log File'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
},
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue