overview

desenvolvemos o givee com o objetivo de centralizar o planejamento de presentes, eliminando a necessidade de notas espalhadas e esquecimentos de última hora. o aplicativo permite criar perfis para cada pessoa importante, registrando datas comemorativas (como aniversários e bodas) e associando ideias de presentes a elas. cada item da lista de presentes pode incluir anotações detalhadas, estimativa de preço e links diretos para compra, funcionando como um assistente pessoal de generosidade.

no backend local, utilizamos SwiftData para criar relacionamentos robustos entre os perfis dos usuários, suas datas importantes e os presentes sugeridos. um diferencial técnico foi a integração com o EventKit, que permite ao usuário exportar as datas cadastradas no app diretamente para o calendário nativo do iOS, garantindo que nenhum aniversário seja esquecido. a interface em SwiftUI foi projetada para ser limpa e eficiente, com funcionalidades de busca e filtros de ordenação para gerenciar listas extensas facilmente.

design choices

palette

paper #F4F2F2
graphite #757575
ocean #80AFBD
mint #7FBD8C
blush #E9B8E8
coral #F8CFC9
marker #F5FF62
citrus #FFDFBB

typography

SF Pro Display / títulos e texto primário
Zebras jogam xadrez com o velho faquir
SF Pro Rounded / rótulos e tom casual
Zebras jogam xadrez com o velho faquir

some fonts used in this project are proprietary and may not display correctly if they are not installed on your system.

rationale

o design do givee se baseia em uma metáfora de caderno digital, utilizando a cor paper (#F4F2F2) para estabelecer um tom caloroso e acessível que reduz a carga cognitiva. ao evitar o branco clínico, o app sugere que o conteúdo é um trabalho em andamento—um rascunho ou bloco de notas pessoal—o que se alinha perfeitamente à natureza bagunçada e iterativa do ato de presentear, onde ideias costumam ser semi-formadas antes da compra final.

o elemento mais distintivo é o uso de cores de destaque (ocean, blush, citrus, etc.) implementadas via ZStacks. no código (como em GiftTitleView e NameSectionView), essas cores aparecem como retângulos deslocados atrás do texto, mimetizando a ação física de usar um marcador de texto. isso cumpre um propósito funcional ao criar uma hierarquia visual clara que atrai o olhar para títulos e nomes, enquanto reforça o sentimento artesanal e tátil que transforma elementos padrão de UI do iOS em algo personalizado.

essa abordagem humanizada continua com o uso de fontes arredondadas, formas de cápsula para datas e visuais de tag com traços suaves. como presentear é algo inerentemente pessoal, evitar uma lista fria e transacional estilo planilha era fundamental. ao estilizar componentes como DateCapsule e TagView com tons de coral e traços macios, o app trata os dados de perfil—nomes, datas e preferências—como entradas valiosas de um scrapbook, não meros pontos de dados. esse design emocional garante que o usuário sinta que está cultivando um relacionamento, e não apenas gerenciando uma lista de tarefas.

tech stack

SwiftUI
framework de UI
SwiftData
persistência local
EventKit
integração com calendário
UIKit
framework de UI

code snippets

Eventos Recorrentes do Calendário

swift
class CalendarManager: ObservableObject {
    private let eventStore = EKEventStore()
    @Published var authorizationStatus: EKAuthorizationStatus = .notDetermined
    
    func requestAccess() {
        eventStore.requestFullAccessToEvents { granted, error in
            DispatchQueue.main.async {
                self.authorizationStatus = granted ? .authorized : .denied
            }
        }
    }
    
    func createEvent(title: String, date: Date) {
        let event = EKEvent(eventStore: eventStore)
        event.title = title
        event.startDate = date
        event.endDate = date
        event.isAllDay = true
        event.calendar = eventStore.defaultCalendarForNewEvents
        
        let recurrenceRule = EKRecurrenceRule(
            recurrenceWith: .yearly,
            interval: 1,
            end: nil
        )
        event.recurrenceRules = [recurrenceRule]
        
        do {
            try eventStore.save(event, span: .thisEvent)
            print("Event Created")
        } catch {
            print("Error creating event: \(error.localizedDescription)")
        }
    }
}

Modelo de Perfil SwiftData

swift
@Model
class ProfileModel: Identifiable {
    var name: String
    var events: [EventDateModel]?
    var bio: String?
    @Relationship(deleteRule: .cascade, inverse: \GiftModel.owner)
    var gifts: [GiftModel] = []
    init(
        name: String,
        events: [EventDateModel]? = nil,
        bio: String? = nil,
        gifts: [GiftModel] = []
    ) {
        self.name = name
        self.events = events
        self.bio = bio
        self.gifts = gifts
    }
}

Vista de Entrada de Título de Presente

swift
struct GiftTitleView: View {
    @Binding var giftTitle: String
    @Binding var name: String
    var body: some View {
        VStack {
            ZStack(alignment: .topTrailing) {
                VStack(spacing: 16) {
                    ZStack {
                        if giftTitle.isEmpty {
                            Text("Title")
                                .font(.system(size: 36, weight: .bold))
                                .foregroundColor(.gray)
                        }
                        TextField("", text: $giftTitle)
                            .font(.system(size: 36, weight: .bold))
                            .multilineTextAlignment(.center)
                    }
                    .background(
                         Rectangle()
                             .fill(Color("Citrus"))
                             .frame(height: 20)
                             .offset(y: 10)
                    )
                    TagView(name: name)
                        .padding(.bottom, 5)
                }
            }
        }
    }
}

credits