fix(android): show password action only for locked channels

This commit is contained in:
Edison Jwa
2026-05-20 14:52:34 +09:00
parent 273eaf21c1
commit f8b6485390
8 changed files with 38 additions and 11 deletions
+8 -7
View File
@@ -2152,13 +2152,14 @@ class _SnapshotView extends StatelessWidget {
: Row( : Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
IconButton( if (ch.hasPassword)
icon: const Icon(Icons.lock_outline), IconButton(
tooltip: l10n.channelPasswordTitle, icon: const Icon(Icons.lock_outline),
onPressed: hasJoinPending tooltip: l10n.channelPasswordTitle,
? null onPressed: hasJoinPending
: () => onJoinChannelWithPassword(ch), ? null
), : () => onJoinChannelWithPassword(ch),
),
IconButton( IconButton(
icon: Icon( icon: Icon(
ch.id == pendingVoiceChannelId ch.id == pendingVoiceChannelId
+11 -2
View File
@@ -314,16 +314,24 @@ class BridgeChannel {
/// Server-side ordering hint. /// Server-side ordering hint.
final PlatformInt64 order; final PlatformInt64 order;
/// True when the server marks the channel as password-protected.
final bool hasPassword;
const BridgeChannel({ const BridgeChannel({
required this.id, required this.id,
required this.parent, required this.parent,
required this.name, required this.name,
required this.order, required this.order,
required this.hasPassword,
}); });
@override @override
int get hashCode => int get hashCode =>
id.hashCode ^ parent.hashCode ^ name.hashCode ^ order.hashCode; id.hashCode ^
parent.hashCode ^
name.hashCode ^
order.hashCode ^
hasPassword.hashCode;
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@@ -333,7 +341,8 @@ class BridgeChannel {
id == other.id && id == other.id &&
parent == other.parent && parent == other.parent &&
name == other.name && name == other.name &&
order == other.order; order == other.order &&
hasPassword == other.hasPassword;
} }
/// Client as seen by Dart. /// Client as seen by Dart.
@@ -1157,13 +1157,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
BridgeChannel dco_decode_bridge_channel(dynamic raw) { BridgeChannel dco_decode_bridge_channel(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
final arr = raw as List<dynamic>; final arr = raw as List<dynamic>;
if (arr.length != 4) if (arr.length != 5)
throw Exception('unexpected arr length: expect 4 but see ${arr.length}'); throw Exception('unexpected arr length: expect 5 but see ${arr.length}');
return BridgeChannel( return BridgeChannel(
id: dco_decode_u_64(arr[0]), id: dco_decode_u_64(arr[0]),
parent: dco_decode_u_64(arr[1]), parent: dco_decode_u_64(arr[1]),
name: dco_decode_String(arr[2]), name: dco_decode_String(arr[2]),
order: dco_decode_i_64(arr[3]), order: dco_decode_i_64(arr[3]),
hasPassword: dco_decode_bool(arr[4]),
); );
} }
@@ -1518,11 +1519,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
var var_parent = sse_decode_u_64(deserializer); var var_parent = sse_decode_u_64(deserializer);
var var_name = sse_decode_String(deserializer); var var_name = sse_decode_String(deserializer);
var var_order = sse_decode_i_64(deserializer); var var_order = sse_decode_i_64(deserializer);
var var_hasPassword = sse_decode_bool(deserializer);
return BridgeChannel( return BridgeChannel(
id: var_id, id: var_id,
parent: var_parent, parent: var_parent,
name: var_name, name: var_name,
order: var_order, order: var_order,
hasPassword: var_hasPassword,
); );
} }
+4
View File
@@ -2021,12 +2021,14 @@ mod tests {
parent: chanora_protocol::ChannelId(0), parent: chanora_protocol::ChannelId(0),
name: "a".into(), name: "a".into(),
order: 0, order: 0,
has_password: false,
}, },
ChannelInfo { ChannelInfo {
id: chanora_protocol::ChannelId(2), id: chanora_protocol::ChannelId(2),
parent: chanora_protocol::ChannelId(0), parent: chanora_protocol::ChannelId(0),
name: "b".into(), name: "b".into(),
order: 1, order: 1,
has_password: false,
}, },
], ],
clients: vec![ClientInfo { clients: vec![ClientInfo {
@@ -2057,12 +2059,14 @@ mod tests {
parent: chanora_protocol::ChannelId(0), parent: chanora_protocol::ChannelId(0),
name: "b".into(), name: "b".into(),
order: 1, order: 1,
has_password: false,
}, },
ChannelInfo { ChannelInfo {
id: chanora_protocol::ChannelId(1), id: chanora_protocol::ChannelId(1),
parent: chanora_protocol::ChannelId(0), parent: chanora_protocol::ChannelId(0),
name: "a".into(), name: "a".into(),
order: 0, order: 0,
has_password: false,
}, },
], ],
clients: vec![], clients: vec![],
+3
View File
@@ -355,6 +355,8 @@ pub struct BridgeChannel {
pub name: String, pub name: String,
/// Server-side ordering hint. /// Server-side ordering hint.
pub order: i64, pub order: i64,
/// True when the server marks the channel as password-protected.
pub has_password: bool,
} }
/// Client as seen by Dart. /// Client as seen by Dart.
@@ -406,6 +408,7 @@ impl From<chanora_protocol::ServerSnapshot> for BridgeSnapshot {
parent: c.parent.0, parent: c.parent.0,
name: c.name, name: c.name,
order: c.order, order: c.order,
has_password: c.has_password,
}) })
.collect(), .collect(),
clients: s clients: s
@@ -1275,11 +1275,13 @@ impl SseDecode for crate::api::BridgeChannel {
let mut var_parent = <u64>::sse_decode(deserializer); let mut var_parent = <u64>::sse_decode(deserializer);
let mut var_name = <String>::sse_decode(deserializer); let mut var_name = <String>::sse_decode(deserializer);
let mut var_order = <i64>::sse_decode(deserializer); let mut var_order = <i64>::sse_decode(deserializer);
let mut var_has_password = <bool>::sse_decode(deserializer);
return crate::api::BridgeChannel { return crate::api::BridgeChannel {
id: var_id, id: var_id,
parent: var_parent, parent: var_parent,
name: var_name, name: var_name,
order: var_order, order: var_order,
has_password: var_has_password,
}; };
} }
} }
@@ -1800,6 +1802,7 @@ impl flutter_rust_bridge::IntoDart for crate::api::BridgeChannel {
self.parent.into_into_dart().into_dart(), self.parent.into_into_dart().into_dart(),
self.name.into_into_dart().into_dart(), self.name.into_into_dart().into_dart(),
self.order.into_into_dart().into_dart(), self.order.into_into_dart().into_dart(),
self.has_password.into_into_dart().into_dart(),
] ]
.into_dart() .into_dart()
} }
@@ -2180,6 +2183,7 @@ impl SseEncode for crate::api::BridgeChannel {
<u64>::sse_encode(self.parent, serializer); <u64>::sse_encode(self.parent, serializer);
<String>::sse_encode(self.name, serializer); <String>::sse_encode(self.name, serializer);
<i64>::sse_encode(self.order, serializer); <i64>::sse_encode(self.order, serializer);
<bool>::sse_encode(self.has_password, serializer);
} }
} }
+1
View File
@@ -864,6 +864,7 @@ fn build_snapshot(con: &Connection) -> Result<ServerSnapshot, ProtocolError> {
parent: ChannelId(c.parent.0), parent: ChannelId(c.parent.0),
name: sanitize(&c.name), name: sanitize(&c.name),
order: c.order.0 as i64, order: c.order.0 as i64,
has_password: c.has_password.unwrap_or(false),
}) })
.collect(); .collect();
+2
View File
@@ -23,6 +23,8 @@ pub struct ChannelInfo {
pub name: String, pub name: String,
/// Server-side ordering hint. /// Server-side ordering hint.
pub order: i64, pub order: i64,
/// True when the server marks the channel as password-protected.
pub has_password: bool,
} }
/// One connected client on the server. /// One connected client on the server.