package handler import ( "context" "fmt" "log/slog" "strings" "github.com/go-telegram/bot/models" "uptodownBot/internal/domain" ) func (h *Handler) buildSettingsKeyboard(userID int64, prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) { mediaTypeLabel := "Video+Audio" switch prefs.DefaultMediaType { case domain.MediaTypeAudio: mediaTypeLabel = "Audio Only" case domain.MediaTypeVideo: mediaTypeLabel = "Video Only" } qualityLabel := prefs.DefaultQuality if qualityLabel == "" { qualityLabel = "best" } containerLabel := prefs.DefaultContainer if containerLabel == "" { containerLabel = "mp4" } langLabel := prefs.DefaultLanguage if langLabel == "" { langLabel = "Default" } rows := [][]models.InlineKeyboardButton{ { {Text: fmt.Sprintf("Type: %s", mediaTypeLabel), CallbackData: "settings_media_type"}, {Text: fmt.Sprintf("Quality: %s", qualityLabel), CallbackData: "settings_quality"}, }, { {Text: fmt.Sprintf("Container: %s", containerLabel), CallbackData: "settings_container"}, {Text: fmt.Sprintf("Language: %s", langLabel), CallbackData: "settings_language"}, }, {{Text: "Delete my data", CallbackData: "delaccount_prompt"}}, {{Text: "Back to Menu", CallbackData: "back_menu"}}, } return "Settings:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } func (h *Handler) settingsCallback(ctx context.Context, chatID int64, msgID int, cbID string, userID int64) { defer h.answerCb(ctx, cbID) prefs, err := h.Repo.GetOrCreatePreferences(userID) if err != nil { return } text, kb := h.buildSettingsKeyboard(userID, prefs) h.editText(ctx, chatID, msgID, text, &kb) } func (h *Handler) backToSettings(ctx context.Context, chatID int64, msgID int, userID int64) { prefs, err := h.Repo.GetOrCreatePreferences(userID) if err != nil { return } text, kb := h.buildSettingsKeyboard(userID, prefs) h.editText(ctx, chatID, msgID, text, &kb) } func (h *Handler) handleSettingsSelection(ctx context.Context, chatID int64, msgID int, userID int64, setting string) { prefs, err := h.Repo.GetOrCreatePreferences(userID) if err != nil { return } switch setting { case "media_type": text, kb := h.buildMediaTypePicker(prefs) h.editText(ctx, chatID, msgID, text, &kb) case "quality": text, kb := h.buildQualityPicker(prefs) h.editText(ctx, chatID, msgID, text, &kb) case "container": text, kb := h.buildContainerPicker(prefs) h.editText(ctx, chatID, msgID, text, &kb) case "language": text, kb := h.buildLanguagePicker(prefs) h.editText(ctx, chatID, msgID, text, &kb) } } func (h *Handler) buildMediaTypePicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) { options := []struct { label string value domain.MediaType data string }{ {"Audio Only", domain.MediaTypeAudio, "settings_set_type_audio"}, {"Video Only", domain.MediaTypeVideo, "settings_set_type_video"}, {"Video+Audio", domain.MediaTypeVideoAudio, "settings_set_type_both"}, } rows := [][]models.InlineKeyboardButton{} for _, opt := range options { label := opt.label if opt.value == prefs.DefaultMediaType { label = "> " + label } rows = append(rows, []models.InlineKeyboardButton{ {Text: label, CallbackData: opt.data}, }) } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select default media type:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } func (h *Handler) buildQualityPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) { qualities := []string{"best", "2160p", "1080p", "720p", "480p", "360p"} rows := [][]models.InlineKeyboardButton{} row := []models.InlineKeyboardButton{} for i, q := range qualities { label := q if q == prefs.DefaultQuality { label = "> " + label } row = append(row, models.InlineKeyboardButton{ Text: label, CallbackData: "settings_set_quality_" + q, }) if len(row) == 3 || i == len(qualities)-1 { rows = append(rows, row) row = nil } } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select default quality:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } func (h *Handler) buildContainerPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) { containers := []string{"mp4", "mkv", "webm", "mp3", "m4a", "opus"} rows := [][]models.InlineKeyboardButton{} row := []models.InlineKeyboardButton{} for i, c := range containers { label := c if c == prefs.DefaultContainer { label = "> " + label } row = append(row, models.InlineKeyboardButton{ Text: label, CallbackData: "settings_set_container_" + c, }) if len(row) == 3 || i == len(containers)-1 { rows = append(rows, row) row = nil } } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select default container:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } func (h *Handler) buildLanguagePicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) { languages := []string{"", "en", "es", "ja", "ko", "fr", "de", "zh", "ar", "pt", "ru"} langLabels := map[string]string{ "": "Default", "en": "English", "es": "Spanish", "ja": "Japanese", "ko": "Korean", "fr": "French", "de": "German", "zh": "Chinese", "ar": "Arabic", "pt": "Portuguese", "ru": "Russian", } rows := [][]models.InlineKeyboardButton{} row := []models.InlineKeyboardButton{} for i, l := range languages { label := langLabels[l] if l == prefs.DefaultLanguage { label = "> " + label } row = append(row, models.InlineKeyboardButton{ Text: label, CallbackData: "settings_set_language_" + l, }) if len(row) == 2 || i == len(languages)-1 { rows = append(rows, row) row = nil } } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select default language:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } func (h *Handler) handleSettingsSet(ctx context.Context, chatID int64, msgID int, userID int64, setting string) { parts := strings.SplitN(setting, "_", 2) if len(parts) < 2 { return } action := parts[0] value := parts[1] prefs, err := h.Repo.GetOrCreatePreferences(userID) if err != nil { return } changed := false switch action { case "type": switch value { case "audio": prefs.DefaultMediaType = domain.MediaTypeAudio case "video": prefs.DefaultMediaType = domain.MediaTypeVideo case "both": prefs.DefaultMediaType = domain.MediaTypeVideoAudio } changed = true case "quality": prefs.DefaultQuality = value changed = true case "container": prefs.DefaultContainer = value changed = true case "language": prefs.DefaultLanguage = value changed = true } if changed { _ = h.Repo.UpdatePreferences(userID, prefs) } h.backToSettings(ctx, chatID, msgID, userID) } // deleteAccountPrompt shows the deletion confirmation prompt. func (h *Handler) deleteAccountPrompt(ctx context.Context, chatID int64, msgID int, userID int64) { kb := deleteConfirmKeyboard(userID) h.editText(ctx, chatID, msgID, "This will permanently delete ALL your data (preferences, quota, history).\nAre you sure?", &kb) } // deleteAccountConfirm permanently deletes all user data. func (h *Handler) deleteAccountConfirm(ctx context.Context, chatID int64, msgID int, userID int64) { if err := h.Repo.DeleteUserData(userID); err != nil { slog.Error("delete user data", "user_id", userID, "error", err) h.editText(ctx, chatID, msgID, "Error deleting data. Please try again.", nil) return } h.editText(ctx, chatID, msgID, "All your data has been deleted. You can start fresh by sending /start.", nil) }