feat: beatiful phone number field

This commit is contained in:
MaximOksiuta
2025-11-21 20:01:13 +03:00
parent aa16f6f63d
commit 66e3ff3953
13 changed files with 732 additions and 168 deletions
+2 -2
View File
@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-11-21T15:23:03.580191Z">
<DropdownSelection timestamp="2025-11-21T16:22:10.584040Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/dany/.android/avd/Medium_Phone.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/max/.android/avd/Pixel_9_Pro.avd" />
</handle>
</Target>
</DropdownSelection>
@@ -0,0 +1,304 @@
package com.prodhack.moscow2025.data.data_providers
import com.prodhack.moscow2025.domain.models.PhoneNumberPattern
object PhoneNumberPatternsProvider {
val phoneNumberPatterns = listOf(
PhoneNumberPattern(name = "+7 Russia", countryCode = "+7", pattern = "(000)-000-00-00", countryCodeISO = "RU"),
PhoneNumberPattern(name = "+39 Italy", countryCode = "+39", pattern = "000-000-0000", countryCodeISO = "IT"),
PhoneNumberPattern(name = "+91 India", countryCode = "+91", pattern = "00000-00000", countryCodeISO = "IN"),
PhoneNumberPattern(name = "+1 United States", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "US"),
PhoneNumberPattern(name = "+44 United Kingdom", countryCode = "+44", pattern = "0000 000 0000", countryCodeISO = "GB"),
PhoneNumberPattern(name = "+30 Greece", countryCode = "+30", pattern = "000 0000 0000", countryCodeISO = "GR"),
PhoneNumberPattern(name = "+357 Cyprus", countryCode = "+357", pattern = "0000 000000", countryCodeISO = "CY"),
PhoneNumberPattern(name = "+93 Afghanistan", countryCode = "+93", pattern = "000-000-0000", countryCodeISO = "AF"),
PhoneNumberPattern(name = "+355 Albania", countryCode = "+355", pattern = "000 000 0000", countryCodeISO = "AL"),
PhoneNumberPattern(name = "+213 Algeria", countryCode = "+213", pattern = "0000 00 00 00", countryCodeISO = "DZ"),
PhoneNumberPattern(name = "+1 American Samoa", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "AS"),
PhoneNumberPattern(name = "+376 Andorra", countryCode = "+376", pattern = "000 000", countryCodeISO = "AD"),
PhoneNumberPattern(name = "+244 Angola", countryCode = "+244", pattern = "000 000 000", countryCodeISO = "AO"),
PhoneNumberPattern(name = "+1 Anguilla", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "AI"),
PhoneNumberPattern(name = "+672 Antarctica", countryCode = "+672", pattern = "000-000", countryCodeISO = "AQ"),
PhoneNumberPattern(name = "+1 Antigua And Barbuda", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "AG"),
PhoneNumberPattern(name = "+54 Argentina", countryCode = "+54", pattern = "000 000-0000", countryCodeISO = "AR"),
PhoneNumberPattern(name = "+374 Armenia", countryCode = "+374", pattern = "00 000000", countryCodeISO = "AM"),
PhoneNumberPattern(name = "+297 Aruba", countryCode = "+297", pattern = "000 0000", countryCodeISO = "AW"),
PhoneNumberPattern(name = "+61 Australia", countryCode = "+61", pattern = "000 000 000", countryCodeISO = "AU"),
PhoneNumberPattern(name = "+43 Austria", countryCode = "+43", pattern = "000 0000000", countryCodeISO = "AT"),
PhoneNumberPattern(name = "+994 Azerbaijan", countryCode = "+994", pattern = "00 000 00 00", countryCodeISO = "AZ"),
PhoneNumberPattern(name = "+1 Bahamas", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "BS"),
PhoneNumberPattern(name = "+973 Bahrain", countryCode = "+973", pattern = "0000 0000", countryCodeISO = "BH"),
PhoneNumberPattern(name = "+880 Bangladesh", countryCode = "+880", pattern = "00000-000000", countryCodeISO = "BD"),
PhoneNumberPattern(name = "+1 Barbados", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "BB"),
PhoneNumberPattern(name = "+375 Belarus", countryCode = "+375", pattern = "00 000-00-00", countryCodeISO = "BY"),
PhoneNumberPattern(name = "+32 Belgium", countryCode = "+32", pattern = "000 00 00 00", countryCodeISO = "BE"),
PhoneNumberPattern(name = "+501 Belize", countryCode = "+501", pattern = "000-0000", countryCodeISO = "BZ"),
PhoneNumberPattern(name = "+229 Benin", countryCode = "+229", pattern = "00 00 00 00", countryCodeISO = "BJ"),
PhoneNumberPattern(name = "+1 Bermuda", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "BM"),
PhoneNumberPattern(name = "+975 Bhutan", countryCode = "+975", pattern = "00 000000", countryCodeISO = "BT"),
PhoneNumberPattern(name = "+591 Bolivia", countryCode = "+591", pattern = "00000000", countryCodeISO = "BO"),
PhoneNumberPattern(name = "+387 Bosnia And Herzegowina", countryCode = "+387", pattern = "00 000 000", countryCodeISO = "BA"),
PhoneNumberPattern(name = "+267 Botswana", countryCode = "+267", pattern = "00 000 000", countryCodeISO = "BW"),
PhoneNumberPattern(name = "+47 Bouvet Island (Norway)", countryCode = "+47", pattern = "000 00 000", countryCodeISO = "BV"),
PhoneNumberPattern(name = "+55 Brazil", countryCode = "+55", pattern = "(00) 00000-0000", countryCodeISO = "BR"),
PhoneNumberPattern(name = "+246 British Indian Ocean Territory", countryCode = "+246", pattern = "000-0000", countryCodeISO = "IO"),
PhoneNumberPattern(name = "+673 Brunei Darussalam", countryCode = "+673", pattern = "000-0000", countryCodeISO = "BN"),
PhoneNumberPattern(name = "+359 Bulgaria", countryCode = "+359", pattern = "00 000 0000", countryCodeISO = "BG"),
PhoneNumberPattern(name = "+226 Burkina Faso", countryCode = "+226", pattern = "00 00 00 00", countryCodeISO = "BF"),
PhoneNumberPattern(name = "+257 Burundi", countryCode = "+257", pattern = "00 00 00 00", countryCodeISO = "BI"),
PhoneNumberPattern(name = "+855 Cambodia", countryCode = "+855", pattern = "00 000 000", countryCodeISO = "KH"),
PhoneNumberPattern(name = "+237 Cameroon", countryCode = "+237", pattern = "00 00 00 00", countryCodeISO = "CM"),
PhoneNumberPattern(name = "+1 Canada", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "CA"),
PhoneNumberPattern(name = "+238 Cape Verde", countryCode = "+238", pattern = "000 00 00", countryCodeISO = "CV"),
PhoneNumberPattern(name = "+599 Caribbean Netherlands", countryCode = "+599", pattern = "000-0000", countryCodeISO = "BQ"),
PhoneNumberPattern(name = "+1 Cayman Islands", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "KY"),
PhoneNumberPattern(name = "+236 Central African Republic", countryCode = "+236", pattern = "00 00 00 00", countryCodeISO = "CF"),
PhoneNumberPattern(name = "+235 Chad", countryCode = "+235", pattern = "00 00 00 00", countryCodeISO = "TD"),
PhoneNumberPattern(name = "+56 Chile", countryCode = "+56", pattern = "00 000 0000", countryCodeISO = "CL"),
PhoneNumberPattern(name = "+86 China", countryCode = "+86", pattern = "000 0000 0000", countryCodeISO = "CN"),
PhoneNumberPattern(name = "+61 Christmas Island", countryCode = "+61", pattern = "0000 0000", countryCodeISO = "CX"),
PhoneNumberPattern(name = "+61 Cocos (Keeling) Islands", countryCode = "+61", pattern = "0000 0000", countryCodeISO = "CC"),
PhoneNumberPattern(name = "+57 Colombia", countryCode = "+57", pattern = "000 0000000", countryCodeISO = "CO"),
PhoneNumberPattern(name = "+269 Comoros", countryCode = "+269", pattern = "00 00000", countryCodeISO = "KM"),
PhoneNumberPattern(name = "+242 Congo", countryCode = "+242", pattern = "00 000 0000", countryCodeISO = "CG"),
PhoneNumberPattern(name = "+243 Congo, The DRC", countryCode = "+243", pattern = "000 000 0000", countryCodeISO = "CD"),
PhoneNumberPattern(name = "+682 Cook Islands", countryCode = "+682", pattern = "00 000", countryCodeISO = "CK"),
PhoneNumberPattern(name = "+506 Costa Rica", countryCode = "+506", pattern = "0000 0000", countryCodeISO = "CR"),
PhoneNumberPattern(name = "+225 Cote D'Ivoire", countryCode = "+225", pattern = "00 000 0000", countryCodeISO = "CI"),
PhoneNumberPattern(name = "+385 Croatia", countryCode = "+385", pattern = "00 000 0000", countryCodeISO = "HR"),
PhoneNumberPattern(name = "+53 Cuba", countryCode = "+53", pattern = "000 000000", countryCodeISO = "CU"),
PhoneNumberPattern(name = "+599 Curacao", countryCode = "+599", pattern = "000-0000", countryCodeISO = "CW"),
PhoneNumberPattern(name = "+357 Cyprus", countryCode = "+357", pattern = "0000 0000", countryCodeISO = "CY"),
PhoneNumberPattern(name = "+420 Czech Republic", countryCode = "+420", pattern = "000 000 000", countryCodeISO = "CZ"),
PhoneNumberPattern(name = "+45 Denmark", countryCode = "+45", pattern = "00 00 00 00", countryCodeISO = "DK"),
PhoneNumberPattern(name = "+253 Djibouti", countryCode = "+253", pattern = "00 00 00 00", countryCodeISO = "DJ"),
PhoneNumberPattern(name = "+1 Dominica", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "DM"),
PhoneNumberPattern(name = "+1 Dominican Republic", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "DO"),
PhoneNumberPattern(name = "+670 East Timor", countryCode = "+670", pattern = "0000 000", countryCodeISO = "TL"),
PhoneNumberPattern(name = "+593 Ecuador", countryCode = "+593", pattern = "00 000 0000", countryCodeISO = "EC"),
PhoneNumberPattern(name = "+20 Egypt", countryCode = "+20", pattern = "00 0000000", countryCodeISO = "EG"),
PhoneNumberPattern(name = "+503 El Salvador", countryCode = "+503", pattern = "0000 0000", countryCodeISO = "SV"),
PhoneNumberPattern(name = "+240 Equatorial Guinea", countryCode = "+240", pattern = "00 000 000", countryCodeISO = "GQ"),
PhoneNumberPattern(name = "+291 Eritrea", countryCode = "+291", pattern = "0 000 000", countryCodeISO = "ER"),
PhoneNumberPattern(name = "+372 Estonia", countryCode = "+372", pattern = "0000 0000", countryCodeISO = "EE"),
PhoneNumberPattern(name = "+251 Ethiopia", countryCode = "+251", pattern = "000 000 0000", countryCodeISO = "ET"),
PhoneNumberPattern(name = "+500 Falkland Islands (Malvinas)", countryCode = "+500", pattern = "00000", countryCodeISO = "FK"),
PhoneNumberPattern(name = "+298 Faroe Islands", countryCode = "+298", pattern = "000 000", countryCodeISO = "FO"),
PhoneNumberPattern(name = "+679 Fiji", countryCode = "+679", pattern = "000 0000", countryCodeISO = "FJ"),
PhoneNumberPattern(name = "+358 Finland", countryCode = "+358", pattern = "00 0000000", countryCodeISO = "FI"),
PhoneNumberPattern(name = "+33 France", countryCode = "+33", pattern = "0 00 00 00 00", countryCodeISO = "FR"),
PhoneNumberPattern(name = "+594 French Guiana", countryCode = "+594", pattern = "0000 0000", countryCodeISO = "GF"),
PhoneNumberPattern(name = "+689 French Polynesia", countryCode = "+689", pattern = "00 00 00", countryCodeISO = "PF"),
PhoneNumberPattern(name = "+262 French Southern Territories", countryCode = "+262", pattern = "000 00 00", countryCodeISO = "TF"),
PhoneNumberPattern(name = "+241 Gabon", countryCode = "+241", pattern = "00 00 00", countryCodeISO = "GA"),
PhoneNumberPattern(name = "+220 Gambia", countryCode = "+220", pattern = "000 0000", countryCodeISO = "GM"),
PhoneNumberPattern(name = "+995 Georgia", countryCode = "+995", pattern = "000 00 00 00", countryCodeISO = "GE"),
PhoneNumberPattern(name = "+49 Germany", countryCode = "+49", pattern = "0000 0000000", countryCodeISO = "DE"),
PhoneNumberPattern(name = "+233 Ghana", countryCode = "+233", pattern = "00 000 0000", countryCodeISO = "GH"),
PhoneNumberPattern(name = "+350 Gibraltar", countryCode = "+350", pattern = "000 00000", countryCodeISO = "GI"),
PhoneNumberPattern(name = "+299 Greenland", countryCode = "+299", pattern = "000 000", countryCodeISO = "GL"),
PhoneNumberPattern(name = "+1 Grenada", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "GD"),
PhoneNumberPattern(name = "+590 Guadeloupe", countryCode = "+590", pattern = "0000 0000", countryCodeISO = "GP"),
PhoneNumberPattern(name = "+1 Guam", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "GU"),
PhoneNumberPattern(name = "+502 Guatemala", countryCode = "+502", pattern = "0000 0000", countryCodeISO = "GT"),
PhoneNumberPattern(name = "+224 Guinea", countryCode = "+224", pattern = "000 00 00 00", countryCodeISO = "GN"),
PhoneNumberPattern(name = "+245 Guinea-Bissau", countryCode = "+245", pattern = "000 0000", countryCodeISO = "GW"),
PhoneNumberPattern(name = "+592 Guyana", countryCode = "+592", pattern = "000 0000", countryCodeISO = "GY"),
PhoneNumberPattern(name = "+509 Haiti", countryCode = "+509", pattern = "00 00 0000", countryCodeISO = "HT"),
PhoneNumberPattern(name = "+672 Heard And Mc Donald Islands", countryCode = "+672", pattern = "000-000", countryCodeISO = "HM"),
PhoneNumberPattern(name = "+379 Holy See (Vatican City State)", countryCode = "+379", pattern = "000 000 0000", countryCodeISO = "VA"),
PhoneNumberPattern(name = "+504 Honduras", countryCode = "+504", pattern = "0000 0000", countryCodeISO = "HN"),
PhoneNumberPattern(name = "+852 Hong Kong", countryCode = "+852", pattern = "0000 0000", countryCodeISO = "HK"),
PhoneNumberPattern(name = "+36 Hungary", countryCode = "+36", pattern = "00 000 0000", countryCodeISO = "HU"),
PhoneNumberPattern(name = "+354 Iceland", countryCode = "+354", pattern = "000 0000", countryCodeISO = "IS"),
PhoneNumberPattern(name = "+506 Costa Rica", countryCode = "+506", pattern = "0000 0000", countryCodeISO = "CR"),
PhoneNumberPattern(name = "+225 Cote D'Ivoire", countryCode = "+225", pattern = "00 000 0000", countryCodeISO = "CI"),
PhoneNumberPattern(name = "+385 Croatia", countryCode = "+385", pattern = "00 000 0000", countryCodeISO = "HR"),
PhoneNumberPattern(name = "+53 Cuba", countryCode = "+53", pattern = "000 000000", countryCodeISO = "CU"),
PhoneNumberPattern(name = "+599 Curacao", countryCode = "+599", pattern = "000-0000", countryCodeISO = "CW"),
PhoneNumberPattern(name = "+357 Cyprus", countryCode = "+357", pattern = "0000 0000", countryCodeISO = "CY"),
PhoneNumberPattern(name = "+420 Czech Republic", countryCode = "+420", pattern = "000 000 000", countryCodeISO = "CZ"),
PhoneNumberPattern(name = "+45 Denmark", countryCode = "+45", pattern = "00 00 00 00", countryCodeISO = "DK"),
PhoneNumberPattern(name = "+253 Djibouti", countryCode = "+253", pattern = "00 00 00 00", countryCodeISO = "DJ"),
PhoneNumberPattern(name = "+1 Dominica", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "DM"),
PhoneNumberPattern(name = "+1 Dominican Republic", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "DO"),
PhoneNumberPattern(name = "+670 East Timor", countryCode = "+670", pattern = "0000 000", countryCodeISO = "TL"),
PhoneNumberPattern(name = "+593 Ecuador", countryCode = "+593", pattern = "00 000 0000", countryCodeISO = "EC"),
PhoneNumberPattern(name = "+20 Egypt", countryCode = "+20", pattern = "00 0000000", countryCodeISO = "EG"),
PhoneNumberPattern(name = "+503 El Salvador", countryCode = "+503", pattern = "0000 0000", countryCodeISO = "SV"),
PhoneNumberPattern(name = "+240 Equatorial Guinea", countryCode = "+240", pattern = "00 000 000", countryCodeISO = "GQ"),
PhoneNumberPattern(name = "+291 Eritrea", countryCode = "+291", pattern = "0 000 000", countryCodeISO = "ER"),
PhoneNumberPattern(name = "+372 Estonia", countryCode = "+372", pattern = "0000 0000", countryCodeISO = "EE"),
PhoneNumberPattern(name = "+251 Ethiopia", countryCode = "+251", pattern = "000 000 0000", countryCodeISO = "ET"),
PhoneNumberPattern(name = "+500 Falkland Islands (Malvinas)", countryCode = "+500", pattern = "00000", countryCodeISO = "FK"),
PhoneNumberPattern(name = "+298 Faroe Islands", countryCode = "+298", pattern = "000 000", countryCodeISO = "FO"),
PhoneNumberPattern(name = "+679 Fiji", countryCode = "+679", pattern = "000 0000", countryCodeISO = "FJ"),
PhoneNumberPattern(name = "+358 Finland", countryCode = "+358", pattern = "00 0000000", countryCodeISO = "FI"),
PhoneNumberPattern(name = "+33 France", countryCode = "+33", pattern = "0 00 00 00 00", countryCodeISO = "FR"),
PhoneNumberPattern(name = "+594 French Guiana", countryCode = "+594", pattern = "0000 0000", countryCodeISO = "GF"),
PhoneNumberPattern(name = "+689 French Polynesia", countryCode = "+689", pattern = "00 00 00", countryCodeISO = "PF"),
PhoneNumberPattern(name = "+262 French Southern Territories", countryCode = "+262", pattern = "000 00 00", countryCodeISO = "TF"),
PhoneNumberPattern(name = "+241 Gabon", countryCode = "+241", pattern = "00 00 00", countryCodeISO = "GA"),
PhoneNumberPattern(name = "+220 Gambia", countryCode = "+220", pattern = "000 0000", countryCodeISO = "GM"),
PhoneNumberPattern(name = "+995 Georgia", countryCode = "+995", pattern = "000 00 00 00", countryCodeISO = "GE"),
PhoneNumberPattern(name = "+49 Germany", countryCode = "+49", pattern = "0000 0000000", countryCodeISO = "DE"),
PhoneNumberPattern(name = "+233 Ghana", countryCode = "+233", pattern = "00 000 0000", countryCodeISO = "GH"),
PhoneNumberPattern(name = "+350 Gibraltar", countryCode = "+350", pattern = "000 00000", countryCodeISO = "GI"),
PhoneNumberPattern(name = "+299 Greenland", countryCode = "+299", pattern = "000 000", countryCodeISO = "GL"),
PhoneNumberPattern(name = "+1 Grenada", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "GD"),
PhoneNumberPattern(name = "+590 Guadeloupe", countryCode = "+590", pattern = "0000 0000", countryCodeISO = "GP"),
PhoneNumberPattern(name = "+1 Guam", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "GU"),
PhoneNumberPattern(name = "+502 Guatemala", countryCode = "+502", pattern = "0000 0000", countryCodeISO = "GT"),
PhoneNumberPattern(name = "+224 Guinea", countryCode = "+224", pattern = "000 00 00 00", countryCodeISO = "GN"),
PhoneNumberPattern(name = "+245 Guinea-Bissau", countryCode = "+245", pattern = "000 0000", countryCodeISO = "GW"),
PhoneNumberPattern(name = "+592 Guyana", countryCode = "+592", pattern = "000 0000", countryCodeISO = "GY"),
PhoneNumberPattern(name = "+509 Haiti", countryCode = "+509", pattern = "00 00 0000", countryCodeISO = "HT"),
PhoneNumberPattern(name = "+672 Heard And Mc Donald Islands", countryCode = "+672", pattern = "000-000", countryCodeISO = "HM"),
PhoneNumberPattern(name = "+379 Holy See (Vatican City State)", countryCode = "+379", pattern = "000 000 0000", countryCodeISO = "VA"),
PhoneNumberPattern(name = "+504 Honduras", countryCode = "+504", pattern = "0000 0000", countryCodeISO = "HN"),
PhoneNumberPattern(name = "+852 Hong Kong", countryCode = "+852", pattern = "0000 0000", countryCodeISO = "HK"),
PhoneNumberPattern(name = "+36 Hungary", countryCode = "+36", pattern = "00 000 0000", countryCodeISO = "HU"),
PhoneNumberPattern(name = "+354 Iceland", countryCode = "+354", pattern = "000 0000", countryCodeISO = "IS"),
PhoneNumberPattern(name = "+62 Indonesia", countryCode = "+62", pattern = "0000 0000 0000", countryCodeISO = "ID"),
PhoneNumberPattern(name = "+98 Iran (Islamic Republic Of)", countryCode = "+98", pattern = "000 0000 000", countryCodeISO = "IR"),
PhoneNumberPattern(name = "+964 Iraq", countryCode = "+964", pattern = "000 000 0000", countryCodeISO = "IQ"),
PhoneNumberPattern(name = "+353 Ireland", countryCode = "+353", pattern = "00 000 0000", countryCodeISO = "IE"),
PhoneNumberPattern(name = "+972 Israel", countryCode = "+972", pattern = "00-000-0000", countryCodeISO = "IL"),
PhoneNumberPattern(name = "+1876 Jamaica", countryCode = "+1876", pattern = "000 000 0000", countryCodeISO = "JM"),
PhoneNumberPattern(name = "+81 Japan", countryCode = "+81", pattern = "00-0000-0000", countryCodeISO = "JP"),
PhoneNumberPattern(name = "+44 Jersey", countryCode = "+44", pattern = "0000 000 0000", countryCodeISO = "JE"),
PhoneNumberPattern(name = "+962 Jordan", countryCode = "+962", pattern = "00 000 0000", countryCodeISO = "JO"),
PhoneNumberPattern(name = "+7 Kazakhstan", countryCode = "+7", pattern = "000 000 00 00", countryCodeISO = "KZ"),
PhoneNumberPattern(name = "+254 Kenya", countryCode = "+254", pattern = "000 000000", countryCodeISO = "KE"),
PhoneNumberPattern(name = "+686 Kiribati", countryCode = "+686", pattern = "00 000", countryCodeISO = "KI"),
PhoneNumberPattern(name = "+850 Korea, D.P.R.O.", countryCode = "+850", pattern = "00 000 000", countryCodeISO = "KP"),
PhoneNumberPattern(name = "+82 Korea, Republic Of", countryCode = "+82", pattern = "00-000-0000", countryCodeISO = "KR"),
PhoneNumberPattern(name = "+383 Kosovo", countryCode = "+383", pattern = "000 000 000", countryCodeISO = "XK"),
PhoneNumberPattern(name = "+965 Kuwait", countryCode = "+965", pattern = "0000 0000", countryCodeISO = "KW"),
PhoneNumberPattern(name = "+996 Kyrgyzstan", countryCode = "+996", pattern = "000 000 000", countryCodeISO = "KG"),
PhoneNumberPattern(name = "+856 Laos", countryCode = "+856", pattern = "00 000 000", countryCodeISO = "LA"),
PhoneNumberPattern(name = "+371 Latvia", countryCode = "+371", pattern = "00 000 000", countryCodeISO = "LV"),
PhoneNumberPattern(name = "+961 Lebanon", countryCode = "+961", pattern = "00 000 000", countryCodeISO = "LB"),
PhoneNumberPattern(name = "+266 Lesotho", countryCode = "+266", pattern = "000 0000", countryCodeISO = "LS"),
PhoneNumberPattern(name = "+231 Liberia", countryCode = "+231", pattern = "00 000 000", countryCodeISO = "LR"),
PhoneNumberPattern(name = "+218 Libya", countryCode = "+218", pattern = "000-0000000", countryCodeISO = "LY"),
PhoneNumberPattern(name = "+423 Liechtenstein", countryCode = "+423", pattern = "000 0000", countryCodeISO = "LI"),
PhoneNumberPattern(name = "+370 Lithuania", countryCode = "+370", pattern = "(00) 000 0000", countryCodeISO = "LT"),
PhoneNumberPattern(name = "+352 Luxembourg", countryCode = "+352", pattern = "000 000 000", countryCodeISO = "LU"),
PhoneNumberPattern(name = "+853 Macau", countryCode = "+853", pattern = "0000 000", countryCodeISO = "MO"),
PhoneNumberPattern(name = "+261 Madagascar", countryCode = "+261", pattern = "00 00 000 00", countryCodeISO = "MG"),
PhoneNumberPattern(name = "+265 Malawi", countryCode = "+265", pattern = "000 00 00 00", countryCodeISO = "MW"),
PhoneNumberPattern(name = "+60 Malaysia", countryCode = "+60", pattern = "00-000 0000", countryCodeISO = "MY"),
PhoneNumberPattern(name = "+960 Maldives", countryCode = "+960", pattern = "000-0000", countryCodeISO = "MV"),
PhoneNumberPattern(name = "+223 Mali", countryCode = "+223", pattern = "0000 0000", countryCodeISO = "ML"),
PhoneNumberPattern(name = "+356 Malta", countryCode = "+356", pattern = "0000 0000", countryCodeISO = "MT"),
PhoneNumberPattern(name = "+692 Marshall Islands", countryCode = "+692", pattern = "000-0000", countryCodeISO = "MH"),
PhoneNumberPattern(name = "+596 Martinique", countryCode = "+596", pattern = "0000 0000", countryCodeISO = "MQ"),
PhoneNumberPattern(name = "+222 Mauritania", countryCode = "+222", pattern = "00 00 00 00", countryCodeISO = "MR"),
PhoneNumberPattern(name = "+230 Mauritius", countryCode = "+230", pattern = "000 0000", countryCodeISO = "MU"),
PhoneNumberPattern(name = "+262 Mayotte", countryCode = "+262", pattern = "00000 000", countryCodeISO = "YT"),
PhoneNumberPattern(name = "+52 Mexico", countryCode = "+52", pattern = "00 0000 0000", countryCodeISO = "MX"),
PhoneNumberPattern(name = "+691 Micronesia, Federated States Of", countryCode = "+691", pattern = "000 0000", countryCodeISO = "FM"),
PhoneNumberPattern(name = "+373 Moldova, Republic Of", countryCode = "+373", pattern = "000 000 000", countryCodeISO = "MD"),
PhoneNumberPattern(name = "+377 Monaco", countryCode = "+377", pattern = "0000 0000", countryCodeISO = "MC"),
PhoneNumberPattern(name = "+976 Mongolia", countryCode = "+976", pattern = "00 00 0000", countryCodeISO = "MN"),
PhoneNumberPattern(name = "+382 Montenegro", countryCode = "+382", pattern = "00 000 000", countryCodeISO = "ME"),
PhoneNumberPattern(name = "+1 Montserrat", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "MS"),
PhoneNumberPattern(name = "+212 Morocco", countryCode = "+212", pattern = "0000-000000", countryCodeISO = "MA"),
PhoneNumberPattern(name = "+258 Mozambique", countryCode = "+258", pattern = "00 000 0000", countryCodeISO = "MZ"),
PhoneNumberPattern(name = "+95 Myanmar (Burma)", countryCode = "+95", pattern = "00 000 000", countryCodeISO = "MM"),
PhoneNumberPattern(name = "+264 Namibia", countryCode = "+264", pattern = "00 000 0000", countryCodeISO = "NA"),
PhoneNumberPattern(name = "+674 Nauru", countryCode = "+674", pattern = "000 0000", countryCodeISO = "NR"),
PhoneNumberPattern(name = "+977 Nepal", countryCode = "+977", pattern = "000-0000000", countryCodeISO = "NP"),
PhoneNumberPattern(name = "+31 Netherlands", countryCode = "+31", pattern = "00 000 0000", countryCodeISO = "NL"),
PhoneNumberPattern(name = "+687 New Caledonia", countryCode = "+687", pattern = "00 0000", countryCodeISO = "NC"),
PhoneNumberPattern(name = "+64 New Zealand", countryCode = "+64", pattern = "000 000 0000", countryCodeISO = "NZ"),
PhoneNumberPattern(name = "+505 Nicaragua", countryCode = "+505", pattern = "0000 0000", countryCodeISO = "NI"),
PhoneNumberPattern(name = "+227 Niger", countryCode = "+227", pattern = "00 00 00 00", countryCodeISO = "NE"),
PhoneNumberPattern(name = "+234 Nigeria", countryCode = "+234", pattern = "000 000 0000", countryCodeISO = "NG"),
PhoneNumberPattern(name = "+683 Niue", countryCode = "+683", pattern = "0000", countryCodeISO = "NU"),
PhoneNumberPattern(name = "+672 Norfolk Island", countryCode = "+672", pattern = "000 000", countryCodeISO = "NF"),
PhoneNumberPattern(name = "+389 North Macedonia", countryCode = "+389", pattern = "00 000 000", countryCodeISO = "MK"),
PhoneNumberPattern(name = "+1 Northern Mariana Islands", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "MP"),
PhoneNumberPattern(name = "+47 Norway", countryCode = "+47", pattern = "000 00 000", countryCodeISO = "NO"),
PhoneNumberPattern(name = "+968 Oman", countryCode = "+968", pattern = "0000 0000", countryCodeISO = "OM"),
PhoneNumberPattern(name = "+92 Pakistan", countryCode = "+92", pattern = "000 0000000", countryCodeISO = "PK"),
PhoneNumberPattern(name = "+680 Palau", countryCode = "+680", pattern = "000 0000", countryCodeISO = "PW"),
PhoneNumberPattern(name = "+970 Palestinian Territory", countryCode = "+970", pattern = "00 000 0000", countryCodeISO = "PS"),
PhoneNumberPattern(name = "+507 Panama", countryCode = "+507", pattern = "000 0000", countryCodeISO = "PA"),
PhoneNumberPattern(name = "+675 Papua New Guinea", countryCode = "+675", pattern = "0000 0000", countryCodeISO = "PG"),
PhoneNumberPattern(name = "+595 Paraguay", countryCode = "+595", pattern = "000 000000", countryCodeISO = "PY"),
PhoneNumberPattern(name = "+51 Peru", countryCode = "+51", pattern = "000 000000", countryCodeISO = "PE"),
PhoneNumberPattern(name = "+63 Philippines", countryCode = "+63", pattern = "0000 000 0000", countryCodeISO = "PH"),
PhoneNumberPattern(name = "+870 Pitcairn", countryCode = "+870", pattern = "000 000 000", countryCodeISO = "PN"),
PhoneNumberPattern(name = "+48 Poland", countryCode = "+48", pattern = "000 000 000", countryCodeISO = "PL"),
PhoneNumberPattern(name = "+351 Portugal", countryCode = "+351", pattern = "000 000 000", countryCodeISO = "PT"),
PhoneNumberPattern(name = "+1 Puerto Rico", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "PR"),
PhoneNumberPattern(name = "+974 Qatar", countryCode = "+974", pattern = "0000 0000", countryCodeISO = "QA"),
PhoneNumberPattern(name = "+262 Reunion", countryCode = "+262", pattern = "00000 000", countryCodeISO = "RE"),
PhoneNumberPattern(name = "+40 Romania", countryCode = "+40", pattern = "000 000 0000", countryCodeISO = "RO"),
PhoneNumberPattern(name = "+7 Russian Federation", countryCode = "+7", pattern = "000-000-00-00", countryCodeISO = "RU"),
PhoneNumberPattern(name = "+250 Rwanda", countryCode = "+250", pattern = "0000 0000", countryCodeISO = "RW"),
PhoneNumberPattern(name = "+1 Saint Kitts And Nevis", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "KN"),
PhoneNumberPattern(name = "+1 Saint Lucia", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "LC"),
PhoneNumberPattern(name = "+1 Saint Vincent And The Grenadines", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "VC"),
PhoneNumberPattern(name = "+685 Samoa", countryCode = "+685", pattern = "00 0000", countryCodeISO = "WS"),
PhoneNumberPattern(name = "+378 San Marino", countryCode = "+378", pattern = "000 0000", countryCodeISO = "SM"),
PhoneNumberPattern(name = "+239 Sao Tome And Principe", countryCode = "+239", pattern = "00 0000", countryCodeISO = "ST"),
PhoneNumberPattern(name = "+966 Saudi Arabia", countryCode = "+966", pattern = "000 000 0000", countryCodeISO = "SA"),
PhoneNumberPattern(name = "+221 Senegal", countryCode = "+221", pattern = "00 000 0000", countryCodeISO = "SN"),
PhoneNumberPattern(name = "+381 Serbia", countryCode = "+381", pattern = "00 0000 000", countryCodeISO = "RS"),
PhoneNumberPattern(name = "+248 Seychelles", countryCode = "+248", pattern = "000 0000", countryCodeISO = "SC"),
PhoneNumberPattern(name = "+232 Sierra Leone", countryCode = "+232", pattern = "00 000000", countryCodeISO = "SL"),
PhoneNumberPattern(name = "+65 Singapore", countryCode = "+65", pattern = "0000 0000", countryCodeISO = "SG"),
PhoneNumberPattern(name = "+599 Sint Maarten", countryCode = "+599", pattern = "000-0000", countryCodeISO = "SX"),
PhoneNumberPattern(name = "+421 Slovakia", countryCode = "+421", pattern = "00 000 0000", countryCodeISO = "SK"),
PhoneNumberPattern(name = "+386 Slovenia", countryCode = "+386", pattern = "00 000 000", countryCodeISO = "SI"),
PhoneNumberPattern(name = "+677 Solomon Islands", countryCode = "+677", pattern = "00000", countryCodeISO = "SB"),
PhoneNumberPattern(name = "+252 Somalia", countryCode = "+252", pattern = "00 000 000", countryCodeISO = "SO"),
PhoneNumberPattern(name = "+27 South Africa", countryCode = "+27", pattern = "00 000 0000", countryCodeISO = "ZA"),
PhoneNumberPattern(name = "+500 South Georgia And South S.S.", countryCode = "+500", pattern = "00000", countryCodeISO = "GS"),
PhoneNumberPattern(name = "+211 South Sudan", countryCode = "+211", pattern = "00 000 0000", countryCodeISO = "SS"),
PhoneNumberPattern(name = "+34 Spain", countryCode = "+34", pattern = "000 00 00 00", countryCodeISO = "ES"),
PhoneNumberPattern(name = "+94 Sri Lanka", countryCode = "+94", pattern = "00 000 0000", countryCodeISO = "LK"),
PhoneNumberPattern(name = "+290 St. Helena", countryCode = "+290", pattern = "0000", countryCodeISO = "SH"),
PhoneNumberPattern(name = "+508 St. Pierre And Miquelon", countryCode = "+508", pattern = "00 00 00", countryCodeISO = "PM"),
PhoneNumberPattern(name = "+249 Sudan", countryCode = "+249", pattern = "00 000 0000", countryCodeISO = "SD"),
PhoneNumberPattern(name = "+597 Suriname", countryCode = "+597", pattern = "000-000", countryCodeISO = "SR"),
PhoneNumberPattern(name = "+47 Svalbard And Jan Mayen Islands", countryCode = "+47", pattern = "000 00 000", countryCodeISO = "SJ"),
PhoneNumberPattern(name = "+268 Swaziland", countryCode = "+268", pattern = "0000 0000", countryCodeISO = "SZ"),
PhoneNumberPattern(name = "+46 Sweden", countryCode = "+46", pattern = "000 00 00 00", countryCodeISO = "SE"),
PhoneNumberPattern(name = "+41 Switzerland", countryCode = "+41", pattern = "00 000 00 00", countryCodeISO = "CH"),
PhoneNumberPattern(name = "+963 Syria", countryCode = "+963", pattern = "000 000 0000", countryCodeISO = "SY"),
PhoneNumberPattern(name = "+886 Taiwan", countryCode = "+886", pattern = "000 0000 000", countryCodeISO = "TW"),
PhoneNumberPattern(name = "+992 Tajikistan", countryCode = "+992", pattern = "00 000 0000", countryCodeISO = "TJ"),
PhoneNumberPattern(name = "+255 Tanzania", countryCode = "+255", pattern = "000 000 000", countryCodeISO = "TZ"),
PhoneNumberPattern(name = "+66 Thailand", countryCode = "+66", pattern = "00 000 0000", countryCodeISO = "TH"),
PhoneNumberPattern(name = "+228 Togo", countryCode = "+228", pattern = "00 00 00 00", countryCodeISO = "TG"),
PhoneNumberPattern(name = "+690 Tokelau", countryCode = "+690", pattern = "0000", countryCodeISO = "TK"),
PhoneNumberPattern(name = "+676 Tonga", countryCode = "+676", pattern = "000 0000", countryCodeISO = "TO"),
PhoneNumberPattern(name = "+1 Trinidad And Tobago", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "TT"),
PhoneNumberPattern(name = "+216 Tunisia", countryCode = "+216", pattern = "00 000 000", countryCodeISO = "TN"),
PhoneNumberPattern(name = "+90 Turkey", countryCode = "+90", pattern = "000 000 0000", countryCodeISO = "TR"),
PhoneNumberPattern(name = "+993 Turkmenistan", countryCode = "+993", pattern = "00 000 000", countryCodeISO = "TM"),
PhoneNumberPattern(name = "+1 Turks And Caicos Islands", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "TC"),
PhoneNumberPattern(name = "+688 Tuvalu", countryCode = "+688", pattern = "0000", countryCodeISO = "TV"),
PhoneNumberPattern(name = "+1 U.S. Minor Islands", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "UM"),
PhoneNumberPattern(name = "+256 Uganda", countryCode = "+256", pattern = "0000 000000", countryCodeISO = "UG"),
PhoneNumberPattern(name = "+380 Ukraine", countryCode = "+380", pattern = "000 000 0000", countryCodeISO = "UA"),
PhoneNumberPattern(name = "+971 United Arab Emirates", countryCode = "+971", pattern = "000 000 0000", countryCodeISO = "AE"),
PhoneNumberPattern(name = "+598 Uruguay", countryCode = "+598", pattern = "0000 0000", countryCodeISO = "UY"),
PhoneNumberPattern(name = "+998 Uzbekistan", countryCode = "+998", pattern = "00 000 0000", countryCodeISO = "UZ"),
PhoneNumberPattern(name = "+678 Vanuatu", countryCode = "+678", pattern = "00000", countryCodeISO = "VU"),
PhoneNumberPattern(name = "+58 Venezuela", countryCode = "+58", pattern = "0000-000000", countryCodeISO = "VE"),
PhoneNumberPattern(name = "+84 Vietnam", countryCode = "+84", pattern = "000 000 0000", countryCodeISO = "VN"),
PhoneNumberPattern(name = "+1 Virgin Islands (British)", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "VG"),
PhoneNumberPattern(name = "+1 Virgin Islands (U.S.)", countryCode = "+1", pattern = "(000) 000-0000", countryCodeISO = "VI"),
PhoneNumberPattern(name = "+681 Wallis And Futuna Islands", countryCode = "+681", pattern = "00 00 00", countryCodeISO = "WF"),
PhoneNumberPattern(name = "+212 Western Sahara", countryCode = "+212", pattern = "000 00 00 00", countryCodeISO = "EH"),
PhoneNumberPattern(name = "+967 Yemen", countryCode = "+967", pattern = "00 000000", countryCodeISO = "YE"),
PhoneNumberPattern(name = "+260 Zambia", countryCode = "+260", pattern = "000 000 000", countryCodeISO = "ZM"),
PhoneNumberPattern(name = "+263 Zimbabwe", countryCode = "+263", pattern = "00 000000", countryCodeISO = "ZW")
)
}
@@ -0,0 +1,8 @@
package com.prodhack.moscow2025.domain.models
data class PhoneNumberPattern(
val name: String,
val countryCode: String,
val pattern: String,
val countryCodeISO: String
)
@@ -0,0 +1,20 @@
package com.prodhack.moscow2025.domain.usecase
import com.prodhack.moscow2025.data.data_providers.PhoneNumberPatternsProvider
import com.prodhack.moscow2025.domain.models.PhoneNumberPattern
import java.util.Locale
import org.koin.core.annotation.Single
@Single
class GetDefaultPhoneNumberPatternUseCase {
fun execute(): PhoneNumberPattern? {
val locale = Locale.getDefault()
return PhoneNumberPatternsProvider.phoneNumberPatterns.find {
it.countryCodeISO.equals(
locale.country,
ignoreCase = true
)
}
}
}
@@ -1,6 +1,8 @@
package com.prodhack.moscow2025.domain.usecase.auth
import android.util.Log
import android.util.Patterns
import com.prodhack.moscow2025.domain.models.PhoneNumberPattern
import org.koin.core.annotation.Single
enum class AuthField {
@@ -24,6 +26,7 @@ data class ValidationResult(
class ValidateAuthFieldsUseCase {
fun validateFillProfile(
chosenPattern: PhoneNumberPattern?,
firstName: String,
lastName: String,
phone: String
@@ -31,7 +34,11 @@ class ValidateAuthFieldsUseCase {
val errors = buildMap {
if (firstName.isBlank()) put(AuthField.FirstName, "Введите имя")
if (lastName.isBlank()) put(AuthField.LastName, "Введите фамилию")
if (!isPhoneValid(phone)) put(AuthField.Phone, "Некорректный номер телефона")
val maxCount = chosenPattern!!.pattern.count { it == '0' }
if (phone.isNotBlank() && !isPhoneValid(phone) && phone.length != maxCount) put(
AuthField.Phone,
"Некорректный номер телефона"
)
}
return ValidationResult(errors)
}
@@ -96,5 +103,5 @@ class ValidateAuthFieldsUseCase {
email.isNotBlank() && Patterns.EMAIL_ADDRESS.matcher(email).matches()
private fun isPhoneValid(phone: String): Boolean =
phone.isNotBlank() && Patterns.PHONE.matcher(phone).matches()
Patterns.PHONE.matcher(phone).matches()
}
@@ -41,7 +41,7 @@ fun TTNamedTextField(
error = error,
singleLine = singleLine,
keyboardOptions = keyboardOptions,
onDone = onDone
onDone = onDone,
)
}
}
@@ -32,6 +32,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.prodhack.moscow2025.R
@@ -41,6 +42,7 @@ import com.prodhack.moscow2025.presentation.utils.ui.noRippleClickable
@Composable
fun TTTextField(
modifier: Modifier = Modifier,
textFieldModifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
value: String,
onValueChange: (String) -> Unit,
@@ -54,26 +56,15 @@ fun TTTextField(
imeAction = ImeAction.Next
),
onDone: (() -> Unit)? = null,
trailingIcon: @Composable () -> Unit = {}
trailingIcon: @Composable () -> Unit = {},
visualTransformation: VisualTransformation = VisualTransformation.None
) {
val typography = MaterialTheme.typography
val colorScheme = MaterialTheme.colorScheme
Box(
Modifier.height(70.dp),
) {
Box(
Modifier
.fillMaxWidth()
.height(56.dp)
.offset(x = 5.dp)
.background(
color = Color.White,
shape = RoundedCornerShape(15.dp)
)
)
FieldWrapper(modifier = modifier) {
OutlinedTextField(
modifier = modifier
modifier = textFieldModifier
.fillMaxWidth()
.offset(y = 5.dp),
value = value,
@@ -87,6 +78,7 @@ fun TTTextField(
fontSize = 14.sp,
)
},
visualTransformation = visualTransformation,
isError = error != null,
supportingText = {
if (error != null) {
@@ -175,20 +167,7 @@ fun <T> TTTextFieldWithDropdown(
var expanded by remember { mutableStateOf(false) }
Box(
modifier.height(70.dp),
) {
Box(
Modifier
.fillMaxWidth()
.height(56.dp)
.offset(x = 5.dp)
.background(
color = Color.White,
shape = RoundedCornerShape(15.dp)
)
)
FieldWrapper(modifier = modifier) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
@@ -306,20 +285,7 @@ fun <T> TTTextFieldWithSearch(
var expanded by remember { mutableStateOf(false) }
Box(
modifier.height(70.dp),
) {
Box(
Modifier
.fillMaxWidth()
.height(56.dp)
.offset(x = 5.dp)
.background(
color = Color.White,
shape = RoundedCornerShape(15.dp)
)
)
FieldWrapper(modifier = modifier) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
@@ -400,3 +366,23 @@ fun <T> TTTextFieldWithSearch(
}
}
}
@Composable
fun FieldWrapper(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
Box(
modifier.height(70.dp),
) {
Box(
Modifier
.fillMaxWidth()
.height(56.dp)
.offset(x = 5.dp)
.background(
color = Color.White,
shape = RoundedCornerShape(15.dp)
)
)
content()
}
}
@@ -1,26 +1,39 @@
package com.prodhack.moscow2025.presentation.screens.fillProfile
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@@ -30,21 +43,28 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.prodhack.moscow2025.R
import com.prodhack.moscow2025.domain.usecase.auth.AuthField
import com.prodhack.moscow2025.presentation.components.standart.BigButton
import com.prodhack.moscow2025.presentation.components.standart.TTPasswordField
import com.prodhack.moscow2025.presentation.components.standart.FieldWrapper
import com.prodhack.moscow2025.presentation.components.standart.TTTextField
import com.prodhack.moscow2025.presentation.theme.Paddings
import com.prodhack.moscow2025.presentation.theme.Shapes
import com.prodhack.moscow2025.presentation.utils.ErrorCollectorScope
import com.prodhack.moscow2025.presentation.utils.PhoneVisualTransformation
import com.prodhack.moscow2025.presentation.utils.UIState
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ErrorCollectorScope.FillProfileScreen(
snackbarHostState: SnackbarHostState,
@@ -54,6 +74,9 @@ fun ErrorCollectorScope.FillProfileScreen(
val typography = MaterialTheme.typography
val colorScheme = MaterialTheme.colorScheme
val sheetState = rememberModalBottomSheetState()
val isSheetOpen = remember { mutableStateOf(false) }
val formState by viewModel.formStateFillProfile.collectAsState()
var errorText by remember { mutableStateOf("") }
@@ -133,22 +156,81 @@ fun ErrorCollectorScope.FillProfileScreen(
value = formState.firstName,
onValueChange = viewModel::onFirstNameChange,
label = "Ваше имя",
error = formState.errors[AuthField.FirstName]
error = formState.errors[AuthField.FirstName],
)
Spacer(Modifier.height(12.dp))
TTTextField(
value = formState.lastName,
onValueChange = viewModel::onLastNameChange,
label = "Ваша фамилия",
error = formState.errors[AuthField.LastName]
error = formState.errors[AuthField.LastName],
)
Spacer(Modifier.height(12.dp))
Row(
modifier = Modifier.height(IntrinsicSize.Min),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(
Paddings.medium
)
) {
FieldWrapper(modifier = Modifier
.width(IntrinsicSize.Min)
.fillMaxHeight()) {
BasicTextField(
modifier = Modifier
.fillMaxSize()
.offset(y = 5.dp)
.padding(bottom = 16.dp)
.background(colorScheme.primary, Shapes.smallRoundedBox)
.clip(Shapes.smallRoundedBox),
value = viewModel.chosenPattern.value?.prefix ?: "",
onValueChange = {},
readOnly = true,
textStyle = TextStyle(
color = colorScheme.onPrimary
),
decorationBox = { innerTextField ->
Row(
modifier = Modifier
.clickable {
isSheetOpen.value = true
}
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier.weight(1f)) {
innerTextField()
}
Icon(
modifier = Modifier.size(15.dp),
painter = painterResource(R.drawable.ic_arr_dropdown),
tint = colorScheme.onPrimary,
contentDescription = null
)
}
}
)
}
TTTextField(
value = formState.phone,
onValueChange = viewModel::onPhoneChange,
label = "Ваш телефон",
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Phone
),
visualTransformation = viewModel.chosenPattern.value?.pattern?.let {
PhoneVisualTransformation(
it,
'0'
)
} ?: VisualTransformation.None,
error = formState.errors[AuthField.Phone]
)
Log.d("Test", formState.errors[AuthField.Phone].toString())
}
Spacer(modifier = Modifier.height(20.dp))
BigButton(
onClick = viewModel::submit,
@@ -160,4 +242,32 @@ fun ErrorCollectorScope.FillProfileScreen(
}
}
if (isSheetOpen.value) {
ModalBottomSheet(
sheetState = sheetState,
onDismissRequest = {
isSheetOpen.value = false
},
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(viewModel.phoneNumberPatterns) { pattern ->
Text(
text = pattern.name,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.clickable {
viewModel.chosenPattern.value = pattern
isSheetOpen.value = false
}
)
}
}
}
}
}
}
@@ -6,17 +6,22 @@ import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.provider.MediaStore
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.viewModelScope
import androidx.paging.map
import coil.ImageLoader
import coil.request.ImageRequest
import com.prodhack.moscow2025.data.data_providers.PhoneNumberPatternsProvider
import com.prodhack.moscow2025.domain.interfaces.GalleryRepository
import com.prodhack.moscow2025.domain.models.UpdateUserData
import com.prodhack.moscow2025.domain.usecase.GetDefaultPhoneNumberPatternUseCase
import com.prodhack.moscow2025.domain.usecase.auth.AuthField
import com.prodhack.moscow2025.domain.usecase.auth.UpdateUserUseCase
import com.prodhack.moscow2025.domain.usecase.auth.ValidateAuthFieldsUseCase
import com.prodhack.moscow2025.presentation.utils.UIState
import com.prodhack.moscow2025.presentation.utils.base.BaseViewModel
import com.prodhack.moscow2025.presentation.utils.convertNumberToPattern
import com.prodhack.moscow2025.presentation.utils.toByteArray
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -62,6 +67,7 @@ data class FillProfileFormState(
class FillProfileViewModel(
private val updateUserUseCase: UpdateUserUseCase,
private val validateAuthFieldsUseCase: ValidateAuthFieldsUseCase,
private val getDefaultPhoneNumberPatternUseCase: GetDefaultPhoneNumberPatternUseCase,
private val galleryRepository: GalleryRepository
) : BaseViewModel() {
private val _formStateFillProfile = MutableStateFlow(FillProfileFormState())
@@ -144,12 +150,28 @@ class FillProfileViewModel(
currentPhoto = photo
}
val chosenPattern = mutableStateOf<UIPhoneNumberPattern?>(null)
val phoneNumberPatterns = mutableStateListOf<UIPhoneNumberPattern>()
fun update() {
// Load default pattern
chosenPattern.value = getDefaultPhoneNumberPatternUseCase.execute()?.mapToUI()
// Load all phone number patterns
phoneNumberPatterns.clear()
phoneNumberPatterns.addAll(PhoneNumberPatternsProvider.phoneNumberPatterns.map { it.mapToUI() })
}
fun submit() {
viewModelScope.launch {
val validation = validateAuthFieldsUseCase.validateFillProfile(
firstName = _formStateFillProfile.value.firstName,
lastName = _formStateFillProfile.value.lastName,
phone = _formStateFillProfile.value.phone
phone = _formStateFillProfile.value.phone,
chosenPattern = chosenPattern.value?.mapToDomain()
)
if (!validation.isValid) {
@@ -163,10 +185,20 @@ class FillProfileViewModel(
UpdateUserData(
firstName = _formStateFillProfile.value.firstName,
lastName = _formStateFillProfile.value.lastName,
phone = _formStateFillProfile.value.phone
phone = chosenPattern.value?.mapToDomain()?.let { phoneNumberPattern ->
convertNumberToPattern(
phoneNumberPattern,
_formStateFillProfile.value.phone
)
}
)
)
result.map { it.id }.collectRequest(_profileFillState)
}
}
init {
update()
}
}
@@ -0,0 +1,32 @@
package com.prodhack.moscow2025.presentation.screens.fillProfile
import com.prodhack.moscow2025.domain.models.PhoneNumberPattern
data class UIPhoneNumberPattern(
val prefix: String,
val name: String,
val countryCode: String,
val pattern: String,
val countryCodeISO: String
) {
fun mapToDomain(): PhoneNumberPattern = PhoneNumberPattern(
name = name,
countryCode = countryCode,
countryCodeISO = countryCodeISO,
pattern = pattern
)
}
fun PhoneNumberPattern.mapToUI(): UIPhoneNumberPattern = UIPhoneNumberPattern(
name = name,
countryCode = countryCode,
countryCodeISO = countryCodeISO,
pattern = pattern,
prefix = getFlagEmoji(countryCodeISO) + " " + countryCode
)
fun getFlagEmoji(code: String): String {
val firstLetter = Character.codePointAt(code, 0) - 0x41 + 0x1F1E6
val secondLetter = Character.codePointAt(code, 1) - 0x41 + 0x1F1E6
return String(Character.toChars(firstLetter)) + String(Character.toChars(secondLetter))
}
@@ -147,7 +147,7 @@ fun ErrorCollectorScope.LoginScreen(
value = formState.email,
onValueChange = viewModel::onEmailChange,
label = "Ваш email",
error = formState.errors[AuthField.Email]
error = formState.errors[AuthField.Email],
)
Spacer(Modifier.height(12.dp))
TTPasswordField(
@@ -1,10 +1,8 @@
package com.prodhack.moscow2025.presentation.screens.register
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -39,13 +37,11 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.prodhack.moscow2025.R
import com.prodhack.moscow2025.domain.usecase.auth.AuthField
import com.prodhack.moscow2025.domain.utils.NetworkError
import com.prodhack.moscow2025.presentation.components.standart.BigButton
import com.prodhack.moscow2025.presentation.components.standart.TTPasswordField
import com.prodhack.moscow2025.presentation.components.standart.TTTextField
import com.prodhack.moscow2025.presentation.utils.ErrorCollectorScope
import com.prodhack.moscow2025.presentation.utils.UIState
import com.prodhack.moscow2025.presentation.utils.ui.noRippleClickable
import org.koin.androidx.compose.koinViewModel
@Composable
@@ -131,7 +127,7 @@ fun ErrorCollectorScope.RegisterScreen(
value = formState.email,
onValueChange = viewModel::onEmailChange,
label = "Ваш email",
error = formState.errors[AuthField.Email]
error = formState.errors[AuthField.Email],
)
Spacer(Modifier.height(12.dp))
TTPasswordField(
@@ -0,0 +1,69 @@
package com.prodhack.moscow2025.presentation.utils
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import com.prodhack.moscow2025.domain.models.PhoneNumberPattern
class PhoneVisualTransformation(val mask: String, val maskNumber: Char) : VisualTransformation {
private val maxLength = mask.count { it == maskNumber }
override fun filter(text: AnnotatedString): TransformedText {
val trimmed = if (text.length > maxLength) text.take(maxLength) else text
val annotatedString = buildAnnotatedString {
if (trimmed.isEmpty()) return@buildAnnotatedString
var maskIndex = 0
var textIndex = 0
while (textIndex < trimmed.length && maskIndex < mask.length) {
if (mask[maskIndex] != maskNumber) {
val nextDigitIndex = mask.indexOf(maskNumber, maskIndex)
append(mask.substring(maskIndex, nextDigitIndex))
maskIndex = nextDigitIndex
}
append(trimmed[textIndex++])
maskIndex++
}
}
return TransformedText(annotatedString, PhoneOffsetMapper(mask, maskNumber))
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PhoneVisualTransformation) return false
if (mask != other.mask) return false
if (maskNumber != other.maskNumber) return false
return true
}
override fun hashCode(): Int {
return mask.hashCode()
}
}
private class PhoneOffsetMapper(val mask: String, val numberChar: Char) : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
var noneDigitCount = 0
var i = 0
while (i < offset + noneDigitCount) {
if (mask[i++] != numberChar) noneDigitCount++
}
return offset + noneDigitCount
}
override fun transformedToOriginal(offset: Int): Int =
offset - mask.take(offset).count { it != numberChar }
}
fun convertNumberToPattern(pattern: PhoneNumberPattern, number: String): String {
var answer = pattern.pattern.replace('0', '*')
for (i in number){
answer = answer.replaceFirst('*', i)
}
return "${pattern.countryCode} $answer"
}