From 70cffe01aaf88a687369a0ee1d235e3cd99e5b89 Mon Sep 17 00:00:00 2001 From: Kamal Kishor Joshi Date: Sat, 6 Apr 2024 23:49:51 +0530 Subject: [PATCH] Save palette screen improvements (#207) * drag and drop support for changing color positions * working drag and drop and lock unlock * fix scrolling for large list of colors * revert to master version --- components/SavePalette.js | 2 +- components/SingleColorView.js | 99 ++++++++++++++++++++++++++--------- screens/ColorListScreen.js | 94 ++++++++++++++++++++++++++++----- 3 files changed, 157 insertions(+), 38 deletions(-) diff --git a/components/SavePalette.js b/components/SavePalette.js index efc44028..1a82a059 100644 --- a/components/SavePalette.js +++ b/components/SavePalette.js @@ -40,7 +40,7 @@ export const SavePalette = (props) => { setTimeout(() => { setIsUnlockProNotification(false); }, 5000); - }, [colorList]); + }, [colorList, isPro]); const [paletteName, setPaletteName] = useState(suggestedName ?? ''); useEffect(() => { diff --git a/components/SingleColorView.js b/components/SingleColorView.js index 9d816a3f..6149a656 100644 --- a/components/SingleColorView.js +++ b/components/SingleColorView.js @@ -1,37 +1,88 @@ import * as React from 'react'; -import { Platform, StyleSheet, Text, Clipboard, TouchableOpacity } from 'react-native'; +import { Platform, StyleSheet, Text, Clipboard, TouchableOpacity, View } from 'react-native'; import { notifyMessage } from '../libs/Helpers'; +import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; +import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; -export class SingleColorView extends React.Component { - render() { - return ( - { - if (Platform?.OS === 'android' || Platform.OS === 'ios') { - notifyMessage(this.props.color.color + ' copied to clipboard!'); - } - Clipboard.setString(this.props.color.color); - }} - style={[styles.container, { backgroundColor: this.props.color.color }]}> - - {this.props.color.color + - (this.props.color.name ? ' (' + this.props.color.name + ')' : '')} - - - ); - } +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'; } +export const SingleColorView = ({ color, onColorChange, drag }) => { + const handlePress = () => { + if (Platform?.OS === 'android' || Platform.OS === 'ios') { + notifyMessage(color.color + ' copied to clipboard!'); + } + Clipboard.setString(color.color); + }; + + const textColor = getContrastColor(color.color); + + return ( + + + {color.color.toUpperCase() + (color.name ? ' (' + color.name + ')' : '')} + + + { + onColorChange({ ...color, color: color.color, locked: !color.locked }); + }}> + + + + + + + + ); +}; + const styles = StyleSheet.create({ container: { - height: 56, - justifyContent: 'center', - alignItems: 'center' + height: 72, + //justifyContent: 'center', + alignItems: 'center', + flex: 1, + flexDirection: 'row' }, colorText: { fontWeight: '700', - backgroundColor: 'rgba(255, 255, 255, .3)', - paddingLeft: 8, + paddingLeft: 16, paddingRight: 8 + }, + actionArea: { + position: 'absolute', + right: 0, + padding: 8, + flex: 1, + flexDirection: 'row' + }, + icon: { + fontSize: 24 + }, + actionAreaItem: { + marginRight: 8, + marginLeft: 8 } }); diff --git a/screens/ColorListScreen.js b/screens/ColorListScreen.js index e5db3bf6..cbdc68bc 100644 --- a/screens/ColorListScreen.js +++ b/screens/ColorListScreen.js @@ -1,15 +1,16 @@ import React, { useLayoutEffect } from 'react'; import { SingleColorView } from '../components/SingleColorView'; -import { ScrollView, StyleSheet, View, Text, Platform } from 'react-native'; +import { StyleSheet, View, Text, Platform } from 'react-native'; import CromaButton from '../components/CromaButton'; -import { logEvent } from '../libs/Helpers'; +import { logEvent, notifyMessage } from '../libs/Helpers'; import { CromaContext } from '../store/store'; import { useTranslation } from 'react-i18next'; +import DraggableFlatList from 'react-native-draggable-flatlist'; export default function ColorListScreen({ navigation }) { const { t } = useTranslation(); - const { colorList } = React.useContext(CromaContext); + const { colorList, setColorList } = React.useContext(CromaContext); const colors = uniqueColors(colorList); useLayoutEffect(() => { @@ -20,22 +21,70 @@ export default function ColorListScreen({ navigation }) { : t('Colors') }); }, []); + const renderItem = ({ item, drag }) => ( + { + const index = colors.findIndex((color) => color.color === updatedColor.color); + const updatedColors = [...colors]; + updatedColors[index] = updatedColor; + setColorList(updatedColors); + }} + key={item.color + '-' + item.locked} + color={item} + drag={drag} + /> + ); + + const onDragEnd = ({ data }) => { + logEvent('drag_end_event_color_list'); + setColorList(data); + }; + const regenerateUnlockedColors = () => { + logEvent('regenerate_unlocked_colors', colors.filter((color) => !color.locked).length); + if (colors.filter((color) => !color.locked).length == 0) { + notifyMessage(t('Please unlock at least one color')); + } else { + // TODO: improve this algorithm. + const newColors = colors.map((color) => { + if (!color.locked) { + color.color = '#' + Math.floor(Math.random() * 16777215).toString(16); + } + return color; + }); + setColorList(newColors); + } + }; logEvent('color_list_screen'); return ( - - - {colors.map((color) => ( - - ))} + + {/* this is to make sure scrolling works */} + + item.color + '-' + item.locked} + onDragEnd={onDragEnd} + autoscrollThreshold={100} + /> + Generate new colors for unlocked colors + { + regenerateUnlockedColors(); + }}> + {t('Generate new colors')} + + { navigation.navigate('SavePalette'); }}> {t('SAVE AS NEW PALETTE')} - + ); } function uniqueColors(colors) { @@ -43,6 +92,9 @@ function uniqueColors(colors) { let uniqueColors = []; colors.forEach((color) => { if (!set.has(color.color)) { + if (color.locked === undefined) { + color.locked = true; + } uniqueColors.push(color); } set.add(color.color); @@ -73,10 +125,26 @@ const CustomHeader = () => { }; const styles = StyleSheet.create({ - listview: { - margin: 8 + container: { + flex: 1, + marginTop: 8, + marginBottom: 8 + }, + hintText: { + fontSize: 12, + color: '#888', + marginTop: 8, + marginBottom: 4, + textAlign: 'center' + }, + separator: { + height: 1, + backgroundColor: '#ccc', + marginVertical: 16, + marginHorizontal: 8 }, - doneButton: { - marginRight: '20%' + button: { + marginLeft: 32, + marginRight: 32 } });