Add ExportOptions.plist for App Store Connect configuration

- Created a new ExportOptions.plist file to define export settings for app distribution.
- Configured the plist with method, team ID, signing style, symbol upload option, and destination.
This commit is contained in:
Zach
2026-07-04 00:45:18 -07:00
parent 0f3961f3a2
commit f4cca2fb1d
16 changed files with 329 additions and 153 deletions
+13 -27
View File
@@ -569,10 +569,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
mainAxisAlignment: isOutgoing
? MainAxisAlignment.end
: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isOutgoing) ...[
_buildAvatar(message.senderName),
_buildAvatar(message.senderName, textScale),
const SizedBox(width: 6),
],
Flexible(
@@ -610,10 +610,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
: EdgeInsets.zero,
child: Text(
message.senderName,
style: MeshTheme.mono(
fontSize: 11,
style: TextStyle(
fontSize: 13 * textScale,
fontWeight: FontWeight.w700,
color: _colorForName(message.senderName),
color: textColor,
),
),
),
@@ -1037,8 +1037,11 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
);
}
Widget _buildAvatar(String senderName) {
return AvatarCircle(name: senderName, size: 32);
Widget _buildAvatar(String senderName, double textScale) {
return AvatarCircle(
name: senderName,
size: (32 * textScale).clamp(28.0, 56.0),
);
}
Widget _buildReplyBanner(double textScale) {
@@ -1202,7 +1205,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
hintText: context.l10n.chat_typeMessage,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
MeshRadii.pill,
MeshRadii.md,
),
borderSide: BorderSide(
color: scheme.outlineVariant,
@@ -1210,7 +1213,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
MeshRadii.pill,
MeshRadii.md,
),
borderSide: BorderSide(
color: scheme.outlineVariant,
@@ -1218,7 +1221,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
MeshRadii.pill,
MeshRadii.md,
),
borderSide: BorderSide(
color: scheme.primary,
@@ -1581,23 +1584,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
.join(',');
}
/// Deterministic name-to-hue mapping consistent with [AvatarCircle].
Color _colorForName(String name) {
const hues = [
MeshPalette.blue,
MeshPalette.magenta,
MeshPalette.signal,
MeshPalette.warn,
Color(0xFF8FA8F0),
Color(0xFF6FD9CE),
];
var h = 0;
for (final c in name.codeUnits) {
h = (h * 31 + c) & 0x7fffffff;
}
return hues[h % hues.length];
}
Future<void> openRegionSelectDialog(Channel channel) async {
// The AppBar subtitle reads the region from the connector inside a
// Consumer, so setChannelRegion's notifyListeners refreshes it directly —
+6 -4
View File
@@ -511,10 +511,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
),
),
const SizedBox(width: 6),
StatusChip(
label: 'CH ${channel.index}',
color: MeshPalette.blue,
fontSize: 10,
Text(
'CH ${channel.index}',
style: MeshTheme.mono(
fontSize: 11,
color: scheme.onSurfaceVariant.withValues(alpha: 0.7),
),
),
],
),
+3 -3
View File
@@ -546,15 +546,15 @@ class _ChatScreenState extends State<ChatScreen> {
decoration: InputDecoration(
hintText: context.l10n.chat_typeMessage,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(MeshRadii.pill),
borderRadius: BorderRadius.circular(MeshRadii.md),
borderSide: BorderSide(color: scheme.outlineVariant),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(MeshRadii.pill),
borderRadius: BorderRadius.circular(MeshRadii.md),
borderSide: BorderSide(color: scheme.outlineVariant),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(MeshRadii.pill),
borderRadius: BorderRadius.circular(MeshRadii.md),
borderSide: BorderSide(
color: scheme.primary,
width: 1.5,
+18 -17
View File
@@ -11,16 +11,16 @@ class MeshPalette {
static const bg3 = Color(0xFF1E293B);
static const bg4 = Color(0xFF334155);
// Lines
static const line = Color(0xFF1E293B);
static const line2 = Color(0xFF334155);
static const line3 = Color(0xFF475569);
// Lines — lifted for clearer element separation on the near-black surface
static const line = Color(0xFF2A3850);
static const line2 = Color(0xFF3B4A61);
static const line3 = Color(0xFF546376);
// Ink
// Ink — muted tones brightened for readable secondary/tertiary text in dark
static const ink = Color(0xFFF8FAFC);
static const ink2 = Color(0xFFCBD5E1);
static const ink3 = Color(0xFF94A3B8);
static const ink4 = Color(0xFF64748B);
static const ink2 = Color(0xFFD5DEE9);
static const ink3 = Color(0xFFAAB6C6);
static const ink4 = Color(0xFF828FA3);
// Signal-quality green (used only for SNR coloring, not UI chrome)
static const signal = Color(0xFF22C55E);
@@ -394,9 +394,9 @@ class MeshTheme {
labelTextStyle: WidgetStateProperty.resolveWith((states) {
final selected = states.contains(WidgetState.selected);
return TextStyle(
fontFamily: MeshFonts.mono,
fontFamilyFallback: MeshFonts.monoFallback,
fontSize: 10,
fontFamily: MeshFonts.sans,
fontFamilyFallback: MeshFonts.sansFallback,
fontSize: 11.5,
fontWeight: selected ? FontWeight.w700 : FontWeight.w500,
letterSpacing: 0.1,
color: selected ? scheme.onPrimary : scheme.onSurfaceVariant,
@@ -582,14 +582,15 @@ class MeshTheme {
);
}
/// Small-caps mono label — used for section accents and chip labels.
/// Section-accent / chip label — sans for legibility, with light tracking
/// to keep the "label" feel that section headers rely on.
static TextStyle accentLabel({Color? color, double? fontSize}) {
return TextStyle(
fontFamily: MeshFonts.mono,
fontFamilyFallback: MeshFonts.monoFallback,
fontSize: fontSize ?? 9.5,
fontWeight: FontWeight.w600,
letterSpacing: 1.8,
fontFamily: MeshFonts.sans,
fontFamilyFallback: MeshFonts.sansFallback,
fontSize: fontSize ?? 11,
fontWeight: FontWeight.w700,
letterSpacing: 0.6,
color: color,
);
}
+7 -12
View File
@@ -6,20 +6,15 @@ Route<T> buildQuickSwitchRoute<T>(Widget page) {
transitionDuration: const Duration(milliseconds: 220),
reverseTransitionDuration: const Duration(milliseconds: 200),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
);
// Pure crossfade — no positional slide, so the shared top chrome
// (app bar + Contacts/Channels toggle) stays rock-steady while switching.
return FadeTransition(
opacity: curved,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.02, 0),
end: Offset.zero,
).animate(curved),
child: child,
opacity: CurvedAnimation(
parent: animation,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
),
child: child,
);
},
);
+5 -4
View File
@@ -11,18 +11,19 @@ class UnreadBadge extends StatelessWidget {
Widget build(BuildContext context) {
final display = count > 9999 ? '9999+' : count.toString();
return Container(
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
constraints: const BoxConstraints(minWidth: 20),
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
alignment: Alignment.center,
decoration: BoxDecoration(
color: MeshPalette.blue.withValues(alpha: 0.18),
color: MeshPalette.alert,
borderRadius: BorderRadius.circular(MeshRadii.pill),
border: Border.all(color: MeshPalette.blue.withValues(alpha: 0.45)),
),
child: Text(
display,
style: MeshTheme.mono(
fontSize: 11,
fontWeight: FontWeight.w700,
color: MeshPalette.blue,
color: Colors.white,
),
),
);