1use std::collections::HashMap;
2
3use anyhow::Result;
4use derive_config::DeriveTomlConfig;
5use inquire::{
6 list_option::ListOption,
7 validator::{ErrorMessage, Validation},
8 Confirm,
9 MultiSelect,
10 Select,
11};
12use serde::{Deserialize, Serialize};
13use strum::{Display, IntoEnumIterator};
14
15use crate::{discord, discord::DEVELOPER_ID, provider::ProviderKind};
16
17#[derive(Display, Deserialize, Serialize, Default)]
18pub enum Attribution {
19 #[strum(to_string = "Anonymously (VRC-LOG Dev)")]
20 #[default]
21 Anonymous,
22 #[strum(to_string = "Discord RPC ({0})")]
23 DiscordRPC(String),
24 #[strum(to_string = "Discord ID (Manual Input)")]
25 DiscordID(String),
26}
27
28impl Attribution {
29 #[must_use]
30 pub fn get_user_id(&self) -> String {
31 match self {
32 Self::Anonymous => DEVELOPER_ID.to_string(),
33 Self::DiscordID(id) => id.clone(),
34 Self::DiscordRPC(id) => discord::get_user()
35 .and_then(|u| u.id)
36 .unwrap_or_else(|| id.clone()),
37 }
38 }
39}
40
41#[derive(DeriveTomlConfig, Deserialize, Serialize, Default)]
42pub struct Settings {
43 pub attribution: Attribution,
44 pub clear_amplitude: bool,
45 pub print_scanned: bool,
46 pub providers: HashMap<ProviderKind, bool>,
47}
48
49impl Settings {
50 pub fn try_wizard() -> Result<Self> {
60 let mut attributions = vec![
61 Attribution::Anonymous,
62 Attribution::DiscordID(String::new()),
63 ];
64 if let Some(user) = discord::get_user() {
65 attributions.insert(1, Attribution::DiscordRPC(user.id.unwrap()));
66 }
67 let attribution = Select::new("How do you want to be credited?", attributions).prompt()?;
68 let providers = {
69 let providers = ProviderKind::iter().collect::<Vec<_>>();
70 let enabled = MultiSelect::new("Select which providers to use:", providers.clone())
71 .with_page_size(providers.len())
72 .with_default(&[0, 1, 2, 3, 4, 5, 6, 7])
73 .with_validator(|list: &[ListOption<&ProviderKind>]| {
74 if list.is_empty() {
75 let message = String::from("You must select at least one.");
76 Ok(Validation::Invalid(ErrorMessage::Custom(message)))
77 } else {
78 Ok(Validation::Valid)
79 }
80 })
81 .prompt()?;
82
83 providers
84 .iter()
85 .map(|provider| (*provider, enabled.contains(provider)))
86 .collect()
87 };
88
89 let clear_amplitude = Confirm::new(
90 "Clear amplitude file after reading? (Helps with privacy by removing tracked data)",
91 )
92 .with_default(true)
93 .prompt()?;
94
95 let print_scanned = Confirm::new(
96 "Print all scanned avatar ids instead of just the uniquely discovered ones",
97 )
98 .with_default(false)
99 .prompt()?;
100
101 Ok(Self {
102 attribution,
103 clear_amplitude,
104 print_scanned,
105 providers,
106 })
107 }
108}