Skip to content

Commit

Permalink
Ai color picker api integration (#211)
Browse files Browse the repository at this point in the history
* basic API integration

* improved UI and add events

* track exceptions
  • Loading branch information
kamalkishor1991 authored Apr 13, 2024
1 parent ed7ac29 commit 7012a49
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 54 deletions.
142 changes: 120 additions & 22 deletions components/AIColorPicker.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,146 @@
// components/AIColorPicker.js
import React, { useState } from 'react';
import { View, TextInput, StyleSheet, ActivityIndicator } from 'react-native';
import CromaButton from './CromaButton';
import {
View,
TextInput,
StyleSheet,
ActivityIndicator,
TouchableOpacity,
Text
} from 'react-native';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import Colors from '../constants/Colors';
import { generateAIColorSuggestions } from '../network/colors';
import { pickTextColorBasedOnBgColor } from '../libs/ColorHelper';
import { logEvent, notifyMessage, sendClientError } from '../libs/Helpers';

export default function AIColorPicker({ color, setColor }) {
export default function AIColorPicker({ setColor }) {
const [query, setQuery] = useState('');
const [loading, setLoading] = useState(false);
const [suggestions, setSuggestions] = useState([]);
const [selectedColor, setSelectedColor] = useState(null);

const generateColorFromQuery = async () => {
setLoading(true);
// TODO: Implement the AI color generation logic based on the query
// For now, let's just simulate an async operation with a delay
await new Promise((resolve) => setTimeout(resolve, 1000));
const randomColor = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
setColor(randomColor);
try {
logEvent('ai_color_picker_query_submitted');
const response = await generateAIColorSuggestions(query);
const colors = response.data.colors;
setSuggestions(colors);
} catch (error) {
console.error('Error generating AI color suggestions:', error);
sendClientError('ai_color_picker_query_submitted', error.message);
notifyMessage('Failed to generate suggestion: ' + error.message + ', please try again.');
}
setLoading(false);
};

const handleColorSelect = (hex) => {
logEvent('ai_color_picker_color_selected');
setColor(hex);
setSelectedColor(hex);
};

return (
<View>
<TextInput
style={styles.textInput}
placeholder="Enter a query"
value={query}
onChangeText={setQuery}
/>
<CromaButton onPress={generateColorFromQuery} disabled={loading}>
{loading ? <ActivityIndicator size="small" color="#ffffff" /> : 'Generate Color'}
</CromaButton>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder="e.g., 'Vibrant sunset by the beach'"
value={query}
onChangeText={setQuery}
/>
<TouchableOpacity
style={styles.generateButton}
onPress={generateColorFromQuery}
disabled={loading}>
{loading ? (
<ActivityIndicator size="small" color={Colors.fabPrimary} />
) : (
<FontAwesome5 name="magic" size={24} color={Colors.fabPrimary} />
)}
</TouchableOpacity>
</View>
<View style={styles.suggestionsContainer}>
{suggestions.length > 0 ? (
suggestions.map(({ name, hex }) => (
<TouchableOpacity
key={hex}
style={[
styles.colorPreview,
{ backgroundColor: hex },
selectedColor === hex && styles.selectedColor
]}
onPress={() => handleColorSelect(hex)}>
<Text style={[styles.colorName, { color: pickTextColorBasedOnBgColor(hex) }]}>
{name}
</Text>
<Text style={[styles.colorHex, { color: pickTextColorBasedOnBgColor(hex) }]}>
{hex}
</Text>
</TouchableOpacity>
))
) : (
<Text style={styles.placeholderText}>Your AI-generated colors will appear here</Text>
)}
</View>
</View>
);
}

const styles = StyleSheet.create({
inputContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 16
},
textInput: {
flex: 1,
height: 40,
borderWidth: 1,
borderColor: 'gray',
borderRadius: 8,
paddingHorizontal: 8,
marginRight: 8
},
generateButton: {
borderWidth: 1,
marginBottom: 16,
paddingHorizontal: 8
borderColor: Colors.fabPrimary,
borderRadius: 8,
padding: 8
},
suggestionsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
minHeight: 100,
alignItems: 'center',
justifyContent: 'center'
},
colorPreview: {
width: '100%',
height: 100,
marginTop: 16
width: 80,
height: 80,
borderRadius: 10,
margin: 5,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
borderWidth: 1,
borderColor: 'gray'
},
selectedColor: {
borderWidth: 2,
borderColor: Colors.fabPrimary
},
colorName: {
fontSize: 12,
fontWeight: 'bold',
marginBottom: 4
},
colorHex: {
fontSize: 10
},
placeholderText: {
color: 'gray',
fontSize: 16
}
});
23 changes: 10 additions & 13 deletions components/ColorPickerModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ export default function ColorPickerModal({ initialColor, onColorSelected, onClos
},
{
key: 'AI',
title: 'AI Color Picker',
component: <AIColorPicker color={color} setColor={setColor} />,
hidden: true
title: 'AI',
component: <AIColorPicker color={color} setColor={setColor} />
},
{
key: 'hex',
Expand All @@ -82,16 +81,14 @@ export default function ColorPickerModal({ initialColor, onColorSelected, onClos
return (
<View style={styles.container}>
<View style={styles.tabContainer}>
{tabs
.filter((tab) => !tab.hidden)
.map((tab) => (
<TouchableOpacity
key={tab.key}
style={[styles.tab, activeTab === tab.key && styles.activeTab]}
onPress={() => setActiveTab(tab.key)}>
<Text style={styles.tabText}>{tab.title}</Text>
</TouchableOpacity>
))}
{tabs.map((tab) => (
<TouchableOpacity
key={tab.key}
style={[styles.tab, activeTab === tab.key && styles.activeTab]}
onPress={() => setActiveTab(tab.key)}>
<Text style={styles.tabText}>{tab.title}</Text>
</TouchableOpacity>
))}
</View>
<ScrollView
contentContainerStyle={styles.scrollViewContent}
Expand Down
2 changes: 1 addition & 1 deletion components/CromaColorPicker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { View, StyleSheet, TextInput, TouchableOpacity } from 'react-native';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import Color from 'pigment/full';
const colors = [
'#f50057',
Expand Down
19 changes: 2 additions & 17 deletions components/SingleColorView.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,7 @@ import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { logEvent } from '../libs/Helpers';
import ColorPickerModal from './ColorPickerModal';

function getContrastColor(bgColor) {
var color = bgColor.charAt(0) === '#' ? bgColor.substring(1, 7) : bgColor;
var r = parseInt(color.substring(0, 2), 16); // hexToR
var g = parseInt(color.substring(2, 4), 16); // hexToG
var b = parseInt(color.substring(4, 6), 16); // hexToB
var uicolors = [r / 255, g / 255, b / 255];
var c = uicolors.map((col) => {
if (col <= 0.03928) {
return col / 12.92;
}
return Math.pow((col + 0.055) / 1.055, 2.4);
});
var L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
return L > 0.179 ? 'black' : 'white';
}
import { pickTextColorBasedOnBgColor } from '../libs/ColorHelper';

export const SingleColorView = ({ color, onColorChange, drag, onRemove, onAdd }) => {
const [modalVisible, setModalVisible] = useState(false);
Expand Down Expand Up @@ -68,7 +53,7 @@ export const SingleColorView = ({ color, onColorChange, drag, onRemove, onAdd })
//notifyMessage('Color selected: ' + hexCode);
onColorChange({ ...color, color: hexCode });
};
const textColor = getContrastColor(color.color);
const textColor = pickTextColorBasedOnBgColor(color.color);
const menuItems = [
{ label: 'Copy Color', onPress: handleCopyColor },
{ label: 'Edit Color', onPress: handleEditColor },
Expand Down
2 changes: 1 addition & 1 deletion components/SliderColorPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
SliderSaturationPicker,
SliderValuePicker
} from 'react-native-slider-color-picker';
import { Dimensions, StyleSheet, View, Text, TextInput } from 'react-native';
import { Dimensions, StyleSheet, View, Text } from 'react-native';

import tinycolor from 'tinycolor2'; // TODO: change tinycolor to pigment
import { logEvent } from '../libs/Helpers';
Expand Down
16 changes: 16 additions & 0 deletions libs/ColorHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
export function pickTextColorBasedOnBgColor(bgColor) {
var color = bgColor.charAt(0) === '#' ? bgColor.substring(1, 7) : bgColor;
var r = parseInt(color.substring(0, 2), 16); // hexToR
var g = parseInt(color.substring(2, 4), 16); // hexToG
var b = parseInt(color.substring(4, 6), 16); // hexToB
var uicolors = [r / 255, g / 255, b / 255];
var c = uicolors.map((col) => {
if (col <= 0.03928) {
return col / 12.92;
}
return Math.pow((col + 0.055) / 1.055, 2.4);
});
var L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
return L > 0.179 ? '#000000' : '#FFFFFF';
}
6 changes: 6 additions & 0 deletions network/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import getAxiosClient from './axios.client';

export const generateAIColorSuggestions = async (query) => {
const axiosClient = await getAxiosClient();
return axiosClient.get('colors/generate_suggestions?query=' + query);
};

0 comments on commit 7012a49

Please sign in to comment.