Skip to content

Commit d7f115a

Browse files
committed
feat Minor release v2.2.3
- Optimized avatar image loading performance for faster rendering - Improved theme selection UI with streamlined button styling - Enhanced base64 image handling for better memory efficiency - Minor bug fixes and stability improvements
1 parent 9b1c372 commit d7f115a

File tree

13 files changed

+120
-106
lines changed

13 files changed

+120
-106
lines changed

.github/workflows/android-release.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,13 @@ jobs:
106106
draft: false
107107
prerelease: false
108108
body: |
109-
# 🚀 Alternate ${{ steps.tag.outputs.tag }} – Feature & Improvement Release
109+
# 🚀 Alternate ${{ steps.tag.outputs.tag }} – Performance & UI Update
110110
111111
## ✨ What's New in ${{ steps.tag.outputs.tag }}
112112
113-
- Added support for adding contact photos
114-
- Caller ID popup now appears on lock screen
113+
- Optimized avatar image loading performance for faster rendering
114+
- Improved theme selection UI with streamlined button styling
115+
- Enhanced base64 image handling for better memory efficiency
115116
- Minor bug fixes and stability improvements
116117
117118
## 📦 Download Options

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ android {
101101
applicationId 'com.lulu786.Alternate'
102102
minSdkVersion rootProject.ext.minSdkVersion
103103
targetSdkVersion rootProject.ext.targetSdkVersion
104-
versionCode 8
105-
versionName "2.2.2"
104+
versionCode 9
105+
versionName "2.2.3"
106106
}
107107

108108
signingConfigs {

android/app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
xmlns:tools="http://schemas.android.com/tools">
33

4-
<!-- Explicitly remove permissions added by expo-file-system -->
5-
<!-- <uses-permission android:name="android.permission.INTERNET" tools:node="remove" /> -->
6-
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
7-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove" /> -->
8-
94
<queries>
105
<intent>
116
<action android:name="android.intent.action.VIEW"/>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<!-- Explicitly remove internet permission in release builds -->
6+
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
7+
</manifest>

app.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"expo": {
33
"name": "Alternate",
44
"slug": "Alternate",
5-
"version": "2.2.2",
5+
"version": "2.2.3",
66
"orientation": "portrait",
77
"scheme": "alternate",
88
"userInterfaceStyle": "automatic",
@@ -17,7 +17,7 @@
1717
}
1818
},
1919
"android": {
20-
"versionCode": 8,
20+
"versionCode": 9,
2121
"adaptiveIcon": {
2222
"foregroundImage": "./assets/icon/adaptive-icon.png",
2323
"monochromeImage": "./assets/icon/adaptive-icon.png",

app/edit-contact.tsx

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import PhoneNumberInput from "@/components/phone-number-input";
22
import PhotoPicker from "@/components/photo-picker";
33
import { additionalFields } from "@/constants/AdditionalFields";
4-
import { getAvatarColor } from "@/lib/avatar-utils";
54
import { getCountryByCode } from "@/lib/countries";
6-
import { Contact, ContactFormData } from "@/lib/types";
5+
import { ContactFormData } from "@/lib/types";
76
import { getFormattedDate, getVisibleFields, trimDialCode } from "@/lib/utils";
87
import useContactStore from "@/store/contactStore";
98
import { router, useLocalSearchParams } from "expo-router";
@@ -34,34 +33,27 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
3433
export default function EditContactScreen() {
3534
const theme = useTheme();
3635
const insets = useSafeAreaInsets();
37-
const { contact: contactParam, index } = useLocalSearchParams();
36+
const { fullPhoneNumber: originalFullPhoneNumber, index } =
37+
useLocalSearchParams();
38+
const contacts = useContactStore.use.contacts();
3839

39-
// Parse the contact from JSON string
40-
const contact: Contact | null = contactParam
41-
? JSON.parse(contactParam as string)
42-
: null;
43-
44-
const originalFullPhoneNumber = contact?.fullPhoneNumber;
45-
const letter = contact?.name?.charAt(0) || "?";
40+
// Find the contact by fullPhoneNumber
41+
const contact = contacts.find(
42+
(c) => c.fullPhoneNumber === originalFullPhoneNumber
43+
);
4644

4745
const updateContact = useContactStore.use.updateContact();
4846
const updateError = useContactStore.use.updateContactError();
4947
const clearUpdateError = useContactStore.use.clearUpdateError();
5048
const [visible, setVisible] = useState(false);
5149
const [visibleFields, setVisibleFields] = useState<Set<string>>(() =>
52-
getVisibleFields(contact)
50+
getVisibleFields(contact!)
5351
);
5452
const [showDatePicker, setShowDatePicker] = useState(false);
5553
const [selectedDate, setSelectedDate] = useState(() =>
5654
contact?.birthday ? new Date(contact.birthday) : new Date()
5755
);
5856

59-
const [avatarBackgroundColor, avatarTextColor] = getAvatarColor(
60-
letter,
61-
theme.dark,
62-
Number(index)
63-
);
64-
6557
const {
6658
control,
6759
handleSubmit,
@@ -204,7 +196,7 @@ export default function EditContactScreen() {
204196
const fullPhoneNumber =
205197
data.phoneNumber.dialCode + data.phoneNumber.number.trim();
206198

207-
const success = await updateContact(originalFullPhoneNumber!, {
199+
const success = await updateContact(originalFullPhoneNumber as string, {
208200
name: data.name.trim(),
209201
fullPhoneNumber: fullPhoneNumber,
210202
phoneNumber: data.phoneNumber.number.trim(),

app/preview-contact.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import whatsappIcon from "@/assets/in-app-icon/whatsapp.png";
33
import Material3Avatar from "@/components/material3-avatar";
44
import CustomNavigationBar from "@/components/navigation-bar";
55
import { getAvatarColor } from "@/lib/avatar-utils";
6-
import { Contact } from "@/lib/types";
76
import {
87
getFormattedDate,
98
getFormattedName,
@@ -40,18 +39,17 @@ export default function PreviewContactScreen() {
4039
const theme = useTheme();
4140
const insets = useSafeAreaInsets();
4241

43-
const { contact: contactParam, index } = useLocalSearchParams();
42+
const { fullPhoneNumber, index } = useLocalSearchParams();
43+
const contacts = useContactStore.use.contacts();
4444
const deleteContact = useContactStore.use.deleteContact();
4545
const deleteError = useContactStore.use.deleteContactError();
4646
const clearDeleteError = useContactStore.use.clearDeleteError;
4747
const [visible, setVisible] = useState(false);
4848
const [open, setOpen] = React.useState(false);
4949
const [isDeleting, setIsDeleting] = useState(false);
5050

51-
// Parse the contact from JSON string
52-
const contact: Contact | null = contactParam
53-
? JSON.parse(contactParam as string)
54-
: null;
51+
// Find the contact by fullPhoneNumber
52+
const contact = contacts.find((c) => c.fullPhoneNumber === fullPhoneNumber);
5553

5654
const letter = contact?.name?.charAt(0).toUpperCase() || "?";
5755
const [avatarBackgroundColor, avatarTextColor] = getAvatarColor(
@@ -164,7 +162,10 @@ export default function PreviewContactScreen() {
164162
onPress: () =>
165163
router.push({
166164
pathname: "/edit-contact",
167-
params: { contact: contactParam, index: index },
165+
params: {
166+
fullPhoneNumber: fullPhoneNumber,
167+
index: index,
168+
},
168169
}),
169170
},
170171
]}

app/settings.tsx

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -181,53 +181,48 @@ export default function SettingsScreen() {
181181
label: "Light",
182182
icon: "white-balance-sunny",
183183
showSelectedCheck: true,
184-
style: {
185-
borderStyle: undefined,
186-
borderWidth: 0,
187-
backgroundColor:
188-
themeMode === "light"
189-
? theme.colors.secondaryContainer
190-
: theme.colors.surfaceVariant,
191-
borderTopRightRadius: 5,
192-
borderBottomRightRadius: 5,
193-
borderRadius: 50,
194-
paddingVertical: 3,
195-
},
184+
style: [
185+
styles.segmentedButton,
186+
styles.segmentedButtonLeft,
187+
{
188+
backgroundColor:
189+
themeMode === "light"
190+
? theme.colors.secondaryContainer
191+
: theme.colors.surfaceVariant,
192+
},
193+
],
196194
},
197195
{
198196
value: "dark",
199197
label: "Dark",
200198
icon: "moon-waning-crescent",
201199
showSelectedCheck: true,
202-
style: {
203-
borderStyle: undefined,
204-
borderWidth: 0,
205-
backgroundColor:
206-
themeMode === "dark"
207-
? theme.colors.secondaryContainer
208-
: theme.colors.surfaceVariant,
209-
marginHorizontal: 3,
210-
borderRadius: 5,
211-
paddingVertical: 3,
212-
},
200+
style: [
201+
styles.segmentedButton,
202+
styles.segmentedButtonMiddle,
203+
{
204+
backgroundColor:
205+
themeMode === "dark"
206+
? theme.colors.secondaryContainer
207+
: theme.colors.surfaceVariant,
208+
},
209+
],
213210
},
214211
{
215212
value: "system",
216213
label: "System",
217214
icon: "laptop",
218215
showSelectedCheck: true,
219-
style: {
220-
borderStyle: undefined,
221-
borderWidth: 0,
222-
backgroundColor:
223-
themeMode === "system"
224-
? theme.colors.secondaryContainer
225-
: theme.colors.surfaceVariant,
226-
borderTopLeftRadius: 5,
227-
borderBottomLeftRadius: 5,
228-
borderRadius: 50,
229-
paddingVertical: 3,
230-
},
216+
style: [
217+
styles.segmentedButton,
218+
styles.segmentedButtonRight,
219+
{
220+
backgroundColor:
221+
themeMode === "system"
222+
? theme.colors.secondaryContainer
223+
: theme.colors.surfaceVariant,
224+
},
225+
],
231226
},
232227
]}
233228
/>
@@ -359,4 +354,22 @@ const styles = StyleSheet.create({
359354
borderTopLeftRadius: 0,
360355
borderTopRightRadius: 0,
361356
},
357+
segmentedButton: {
358+
borderStyle: undefined,
359+
borderWidth: 0,
360+
},
361+
segmentedButtonLeft: {
362+
borderTopRightRadius: 3,
363+
borderBottomRightRadius: 3,
364+
borderRadius: 50,
365+
},
366+
segmentedButtonMiddle: {
367+
marginHorizontal: 2,
368+
borderRadius: 3,
369+
},
370+
segmentedButtonRight: {
371+
borderTopLeftRadius: 3,
372+
borderBottomLeftRadius: 3,
373+
borderRadius: 50,
374+
},
362375
});

components/contact-item.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const ContactItem: React.FC<ContactItemProps> = ({
4848
} else {
4949
router.push({
5050
pathname: "/preview-contact",
51-
params: { contact: JSON.stringify(contact), index },
51+
params: { fullPhoneNumber: contact.fullPhoneNumber, index },
5252
});
5353
}
5454
};

components/material3-avatar.tsx

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// import { Image } from "expo-image";
22
import React from "react";
3-
import { StyleProp, View, ViewStyle } from "react-native";
3+
import { StyleProp, ViewStyle } from "react-native";
44
import { useTheme } from "react-native-paper";
55
import Svg, { ClipPath, Defs, Image, Path, Text } from "react-native-svg";
66

@@ -29,34 +29,32 @@ const Material3Avatar = ({
2929

3030
if (photo) {
3131
return (
32-
<View>
33-
<Svg
34-
height={size}
35-
width={size}
36-
viewBox={`0 0 ${size} ${size}`}
37-
style={style}
38-
>
39-
{/* 1. Define the clipping path */}
40-
<Defs>
41-
<ClipPath id="myClipPath">
42-
{/* This path creates a rectangle with a diagonal slice at the top right */}
43-
<Path
44-
d={pathData}
45-
fill={backgroundColor || theme.colors.surfaceVariant}
46-
/>
47-
</ClipPath>
48-
</Defs>
32+
<Svg
33+
height={size}
34+
width={size}
35+
viewBox={`0 0 ${size} ${size}`}
36+
style={style}
37+
>
38+
{/* 1. Define the clipping path */}
39+
<Defs>
40+
<ClipPath id="myClipPath">
41+
{/* This path creates a rectangle with a diagonal slice at the top right */}
42+
<Path
43+
d={pathData}
44+
fill={backgroundColor || theme.colors.surfaceVariant}
45+
/>
46+
</ClipPath>
47+
</Defs>
4948

50-
{/* 2. Apply the clipping path to the image */}
51-
<Image
52-
href={{ uri: photo }}
53-
width="100%"
54-
height="100%"
55-
preserveAspectRatio="xMidYMid slice"
56-
clipPath="url(#myClipPath)"
57-
/>
58-
</Svg>
59-
</View>
49+
{/* 2. Apply the clipping path to the image */}
50+
<Image
51+
href={{ uri: photo }}
52+
width="100%"
53+
height="100%"
54+
preserveAspectRatio="xMidYMid slice"
55+
clipPath="url(#myClipPath)"
56+
/>
57+
</Svg>
6058
);
6159
}
6260

0 commit comments

Comments
 (0)