diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..0565346 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,68 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'kotlin-kapt' +} + +android { + compileSdk 33 + + defaultConfig { + applicationId "com.bulletin" + minSdk 21 + targetSdk 33 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = 11 + } + buildFeatures { + viewBinding true + } +} + + +ext { + appCompat='1.4.1' + materialDesign='1.6.0' + vectorDrawable='1.1.0' + multiDex='2.0.1' + jUnit='4.13.2' + runner='1.4.0' + playCore='1.10.3' + retrofit='2.9.0' + espressoCore='3.4.0' +} +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$appCompat" + implementation "com.google.android.material:material:$materialDesign" + implementation "androidx.vectordrawable:vectordrawable:$vectorDrawable" + implementation "androidx.multidex:multidex:$multiDex" + implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: []) + implementation 'androidx.databinding:viewbinding:7.4.0' + testImplementation "junit:junit:$jUnit" + androidTestImplementation "androidx.test:runner:$runner" + implementation "com.google.android.play:core:$playCore" + androidTestImplementation "androidx.test.espresso:espresso-core:$espressoCore" + + implementation "com.squareup.retrofit2:converter-gson:$retrofit" + + implementation 'com.github.bumptech.glide:glide:4.13.2' + kapt 'com.github.bumptech.glide:compiler:4.13.2' + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/bulletin/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/bulletin/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b260604 --- /dev/null +++ b/app/src/androidTest/java/com/example/bulletin/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.bulletin + +import androidx.test.platform.app.InstrumentationRegistry +//import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +//@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.bulletin", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0d1de19 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/bulletin/BulletinApp.kt b/app/src/main/java/com/bulletin/BulletinApp.kt new file mode 100644 index 0000000..bbd8065 --- /dev/null +++ b/app/src/main/java/com/bulletin/BulletinApp.kt @@ -0,0 +1,29 @@ +package com.bulletin + +import android.app.Application +import android.content.Context +import android.content.pm.PackageManager +import android.util.Log +import com.bulletin.utilities.GsonHelper +import com.google.gson.Gson + +class BulletinApp : Application() { + private var gsonInstance: Gson? = null + + companion object { + lateinit var shared: BulletinApp + private set + + val applicationContext: Context + get() { + return shared.applicationContext + } + } + + //Initializer + init { + shared = this + gsonInstance = GsonHelper.gsonInstance + } + +} diff --git a/app/src/main/java/com/bulletin/BulletinDataStore.kt b/app/src/main/java/com/bulletin/BulletinDataStore.kt new file mode 100644 index 0000000..94d5120 --- /dev/null +++ b/app/src/main/java/com/bulletin/BulletinDataStore.kt @@ -0,0 +1,86 @@ +package com.bulletin + +import com.bulletin.extension.lastSeenVersion +import com.bulletin.models.BulletinInfo +import com.bulletin.models.BulletinItem +import com.bulletin.models.Version +import com.bulletin.utilities.AppStorageHelper +import com.bulletin.utilities.VersionUtil +import java.util.* + + +class BulletinDataStore { + + var data: MutableList = mutableListOf() + private set + + fun registerVersionInfo11(version: Version, items: MutableList>) { + + val bulletinItems = ArrayList() + for (itemAttributes in items) { + val bulletinItem = BulletinItem.createBulletinItem(itemAttributes) ?: return continue + bulletinItems.add(bulletinItem) + } + + registerVersionInfo(version, bulletinItems) + } + + fun registerVersionInfo(version: Version, items: MutableList?) { + + if (items == null || items.isEmpty()) { + return + } + + // Create Bulletin Info Object + val bulletinInfo = BulletinInfo.init(version, items) + + data.add(bulletinInfo) + Collections.sort(data, BulletinInfo.descendingSort) + } + + + fun getData( + fromNewVersion: Version?, + toOldVersion: Version?, + limit: Int? = null + ): ArrayList { + // val finalMap: MutableList = mutableListOf() + val bulletinInfo = arrayListOf() + + if (fromNewVersion == null && toOldVersion == null && limit == null) { + + bulletinInfo.addAll(data) + return bulletinInfo + } else if (fromNewVersion == null && toOldVersion == null && limit != null) { + bulletinInfo.addAll(data.take(limit)) + return bulletinInfo + } + + val sortedList = data.sortedWith(compareBy({ + it.version.version + })) + + for (indice in sortedList.indices) { + + if (indice == 0) AppStorageHelper.shared.lastSeenVersion = + Version.init(sortedList[indice].version.version) + if (VersionUtil.versionCompare( + fromNewVersion?.version, + sortedList[indice].version.version + ) >= 0 + ) { + bulletinInfo.add(sortedList[indice]) + } else if (VersionUtil.versionCompare( + toOldVersion?.version, + sortedList[indice].version.version + ) < 0 + ) { + bulletinInfo.add(sortedList[indice]) + } + + if (limit != null && bulletinInfo.size >= limit) break + + } + return bulletinInfo + } +} diff --git a/app/src/main/java/com/bulletin/BulletinDialog.kt b/app/src/main/java/com/bulletin/BulletinDialog.kt new file mode 100644 index 0000000..e494049 --- /dev/null +++ b/app/src/main/java/com/bulletin/BulletinDialog.kt @@ -0,0 +1,179 @@ +package com.example.bulletin + +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.util.Size +import android.view.* +import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.models.* +import com.bulletin.utilities.ThemeUtils +import com.bulletin.utilities.ViewUtil +import com.example.bulletin.databinding.BulletinDialogBinding +import com.wrx.wazirx.views.bulletin.model.Media +import java.util.* + + +class BulletinDialog(var bulletinInfo: ArrayList = ArrayList()) : DialogFragment() , FormRecyclerViewAdapter.OnItemClickListener { + + // region Variables +// private lateinit var binding: BulletinDialogBinding + private var _binding: BulletinDialogBinding? = null + // This property is only valid between onCreateDialog and + // onDestroyView. + private val binding get() = _binding!! + private lateinit var formRecyclerViewAdapter: FormRecyclerViewAdapter + public var bulletinListener : BulletinListener? = null + // private var bulletinInfo: ArrayList = ArrayList() + // endregion + + override fun onCreate(savedInstanceState: Bundle?) { +// setStyle(STYLE_NO_TITLE, R.style.Theme_Transparent) + +// Window.setLayout( +// WindowManager.LayoutParams.MATCH_PARENT, +// WindowManager.LayoutParams.MATCH_PARENT); + + setStyle(STYLE_NO_TITLE, android.R.style.Theme_Black_NoTitleBar_Fullscreen) + + // context?.setTheme(R.style.AppThemeBase_WhiteKnight) + super.onCreate(savedInstanceState) + + setupClickEvent() + +// (intent.extras?.getSerializable("BulletinInfo") as? ArrayList)?.let { +// for (dict in it) { +// for (bulletinfo in dict.items) { +// bulletinInfo.add(bulletinfo) +// } +// } +// +// } + + + } + +// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { +// _binding = DialogExampleBinding.inflate(LayoutInflater.from(context)) +// return AlertDialog.Builder(requireActivity()) +// .setView(binding.root) +// .create() +// } + + private fun setupClickEvent() { + binding.goItButton.setOnClickListener { closeClicked() } + } + + private fun closeClicked() { + bulletinListener?.backButtonClick() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) +// val view: View = inflater.inflate(R.layout.bulletin_dialog, container, false) +// _binding = BulletinDialogBinding.inflate(LayoutInflater.from(context)) +// binding.listView.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.main_bg_surface_alt, binding.listView.context)) +// return view + _binding = BulletinDialogBinding.inflate(inflater, container, false) + val root: View = binding.root + return root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + loadDisplayContent() + updateAppearance() + recyclerViewSetUp() + } + + fun loadDisplayContent() { + ViewUtil.addBounceEffect(binding.goItButton) + setupButtonClickEvent() + } + + fun updateAppearance() { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + binding.headerTitle.setTextAppearance(R.style.large_semi_bold) + binding.goItButton.setTextAppearance(R.style.base_bold) + } else { + binding.headerTitle.setTextAppearance(binding.headerTitle.context,R.style.large_semi_bold) + binding.goItButton.setTextAppearance(binding.goItButton.context,R.style.base_bold) + } + + binding.headerTitle.setTextColor(ThemeUtils.getAttributedColor(R.attr.main_navigation_onNavigation, binding.headerTitle.context)) + + binding.listView.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.main_bg_surface_alt, binding.listView.context)) + binding.goItButton.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.brand_bg_primary, binding.goItButton.context)) + + ThemeUtils.applyThemeDrawable(binding.headerView, R.attr.main_navigation_bg) + ThemeUtils.applyThemeDrawable(binding.mainBackgroundView, R.attr.main_bg_surface_alt) + + } + + fun recyclerViewSetUp(){ + val layoutManager = LinearLayoutManager(context) + layoutManager.orientation = LinearLayoutManager.VERTICAL + binding.listView.setLayoutManager(layoutManager) + + formRecyclerViewAdapter = FormRecyclerViewAdapter(bulletinInfo,this) + binding.listView.setAdapter(formRecyclerViewAdapter) + } + + fun setUpItems() : ArrayList { + val title = Title("Version " + "1.21",Color.RED,"In this update","loreum ipsum loreum ipsum loreum ipsum loreum ipsum loreum ipsum") + + val message = Message(Message.MessageType.HTML,"
\n" + + "

Harry Potter's House

\n" + + "

\n" + + "Privet Drive, 4
Little Whinging
Surrey
England
Great Britain\n" + + "

\n" + + "
") + + val size = Size(700,500) + val media = Media(Media.MediaType.IMAGE,"https://media.wazirx.com/test_resources/crypto_gifts.png",null) + + val bullet = Bullet(Bullet.BulletType.IMAGE,"\uD83D\uDE01","https://s3.amazonaws.com/p.hellopye.com/app_assets/dashboard_deposit/3x.png") //"\u00F6" //"✋" + + val bulletPoint = BulletPoint(bullet,"Vestibulum","Etiam porta sem malesuada magna mollis euismod.") + + val bulletPoint2 = BulletPoint(bullet,"Justo Condimentum","Sed posuere consectetur est at lobortis. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.") + + val actionButton = ActionButton("Take me to Crypto Gifts",null) + + return arrayListOf(title, message) // media, bulletPoint, bulletPoint2, actionButton + + } + + fun setupButtonClickEvent() { + binding.goItButton.setOnClickListener { + // Back event need to handle + } + } + + override fun formDidTriggerEvent( + eventType: BulletinItem.EventType, + baseItem: BulletinItem, + index: Int + ): Boolean { + bulletinListener?.onButtonClick("") + return true + } + + interface BulletinListener { + fun onButtonClick(response: String) + fun backButtonClick() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bulletin/BulletinSdk.kt b/app/src/main/java/com/bulletin/BulletinSdk.kt new file mode 100644 index 0000000..f99e069 --- /dev/null +++ b/app/src/main/java/com/bulletin/BulletinSdk.kt @@ -0,0 +1,84 @@ +package com.bulletin + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.ContextCompat +import com.bulletin.extension.lastSeenVersion +import com.bulletin.models.BulletinInfo +import com.bulletin.models.BulletinItem +import com.bulletin.utilities.AppStorageHelper +import com.example.bulletin.BulletinDialog +import com.example.bulletin.DefaultActivity +import com.example.bulletin.R + + +enum class Appearance(val value: String) { + DARK("dark"), + LIGHT("light"); +} + +object AppTheme { + var appearance: Appearance = Appearance.DARK + + fun getCurrentTheme(): Int { + + return when (appearance) { + Appearance.DARK -> R.style.AppThemeBase_DarkKnight + Appearance.LIGHT -> R.style.AppThemeBase_WhiteKnight + } + } +} + +class BulletinSdk(val dataStore: BulletinDataStore, val theme : Appearance) { + + fun getFullBulletin(context: Context,listner : BulletinDialog.BulletinListener) : BulletinDialog? { + val items = dataStore.getData(null, null) + return getBulletin(context, items,listner) + } + + + fun getLastBulletins(context: Context, limit: Int? = 1,listner : BulletinDialog.BulletinListener): BulletinDialog? { + val items = dataStore.getData(null, null, limit) + return getBulletin(context, items,listner) + } + + fun getUnseenBulletin(context: Context, limit: Int? = null,listner : BulletinDialog.BulletinListener): BulletinDialog? { + val lastseenVersion = AppStorageHelper.shared.lastSeenVersion ?: return null + val items = dataStore.getData(lastseenVersion, null, limit) + return getBulletin(context, items,listner) + } + + fun getBulletin(context: Context,item: ArrayList?, listner : BulletinDialog.BulletinListener): BulletinDialog? { + if (item == null || item.isEmpty()) return null; + +// when (theme) { +// Appearance.DARK -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) +// Appearance.LIGHT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) +// Appearance.SYSTEM -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) +// } + + AppTheme.appearance = theme + +// val mainIntent = Intent(context, MainActivity::class.java) +// val bundle = Bundle() +// bundle.putSerializable("BulletinInfo", item) +// mainIntent.putExtras(bundle) +// startActivity(context, mainIntent, null) + + val bulletinItems: ArrayList = ArrayList() + + item.forEach { bulletItem -> + for (bulletinItem in bulletItem.items) { + bulletinItems.add(bulletinItem) + } + } + + val bulletinDialog = BulletinDialog(bulletinItems) + bulletinDialog.bulletinListener = listner + + return bulletinDialog + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bulletin/DefaultActivity.kt b/app/src/main/java/com/bulletin/DefaultActivity.kt new file mode 100644 index 0000000..10df314 --- /dev/null +++ b/app/src/main/java/com/bulletin/DefaultActivity.kt @@ -0,0 +1,125 @@ +package com.example.bulletin + +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.util.Size +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.LinearLayoutManager +import com.bulletin.AppTheme +import com.bulletin.Appearance +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.textAppearence +import com.bulletin.models.* +import com.bulletin.utilities.ThemeUtils +import com.bulletin.utilities.ViewUtil +import com.example.bulletin.databinding.ActivityMainBinding +import com.wrx.wazirx.views.bulletin.model.Media + +class DefaultActivity : AppCompatActivity(){ + + // region Variables + private lateinit var binding: ActivityMainBinding + private lateinit var formRecyclerViewAdapter: FormRecyclerViewAdapter + private var bulletinInfo: ArrayList = ArrayList() + // endregion + + override fun onCreate(savedInstanceState: Bundle?) { + + when (AppTheme.appearance) { + Appearance.DARK -> setTheme(R.style.AppThemeBase_DarkKnight) + Appearance.LIGHT -> setTheme(R.style.AppThemeBase_WhiteKnight) + } + + super.onCreate(savedInstanceState) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + // binding.listView.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.main_bg_surface_alt, binding.listView.context)) + + (intent.extras?.getSerializable("ABC") as? ArrayList)?.let { + for (dict in it) { + for (bulletinfo in dict.items) { + bulletinInfo.add(bulletinfo) + } + } + + } + +// loadDisplayContent() +// updateAppearance() +// recyclerViewSetUp() + } + +// fun loadDisplayContent() { +// // ViewUtil.addBounceEffect(binding.goItButton) +// setupButtonClickEvent() +// } + +// fun updateAppearance() { +// +// binding.headerTitle.textAppearence(R.style.large_semi_bold) +// binding.goItButton.textAppearence(R.style.base_bold) +// +// binding.headerTitle.setTextColor(ThemeUtils.getAttributedColor(R.attr.main_navigation_onNavigation, binding.headerTitle.context)) +// +// binding.listView.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.main_bg_surface_alt, binding.listView.context)) +// binding.goItButton.setBackgroundColor(ThemeUtils.getAttributedColor(R.attr.brand_bg_primary, binding.goItButton.context)) +// +// ThemeUtils.applyThemeDrawable(binding.headerView, R.attr.main_navigation_bg) +// ThemeUtils.applyThemeDrawable(binding.mainBackgroundView, R.attr.main_bg_surface_alt) +// +// } + +// fun recyclerViewSetUp(){ +// val layoutManager = LinearLayoutManager(this) +// layoutManager.orientation = LinearLayoutManager.VERTICAL +// binding.listView.setLayoutManager(layoutManager) +// +// formRecyclerViewAdapter = FormRecyclerViewAdapter(setUpItems(),this) +// binding.listView.setAdapter(formRecyclerViewAdapter) +// } + + fun setUpItems() : ArrayList { + + val title = Title("Version " + "1.21", Color.RED,"In this update","loreum ipsum loreum ipsum loreum ipsum loreum ipsum loreum ipsum") + + val message = Message(Message.MessageType.HTML,"
\n" + + "

Harry Potter's House

\n" + + "

\n" + + "Privet Drive, 4
Little Whinging
Surrey
England
Great Britain\n" + + "

\n" + + "
") + + val size = Size(700,500) + val media = Media(Media.MediaType.IMAGE,"https://media.wazirx.com/test_resources/crypto_gifts.png",null) + + val bullet = Bullet(Bullet.BulletType.IMAGE,"\uD83D\uDE01","https://s3.amazonaws.com/p.hellopye.com/app_assets/dashboard_deposit/3x.png") //"\u00F6" //"✋" + + val bulletPoint = BulletPoint(bullet,"Vestibulum","Etiam porta sem malesuada magna mollis euismod.") + + val bulletPoint2 = BulletPoint(bullet,"Justo Condimentum","Sed posuere consectetur est at lobortis. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.") + + val actionButton = ActionButton("Take me to Crypto Gifts",null) + + return arrayListOf(title, message) // media, bulletPoint, bulletPoint2, actionButton + + } + +// fun setupButtonClickEvent() { +// binding.goItButton.setOnClickListener { +// // Back event need to handle +// finish() +// } +// } +// +// override fun formDidTriggerEvent( +// eventType: BulletinItem.EventType, +// baseItem: BulletinItem, +// index: Int +// ): Boolean { +// return true +// } + +} diff --git a/app/src/main/java/com/bulletin/FormRecyclerViewAdapter.kt b/app/src/main/java/com/bulletin/FormRecyclerViewAdapter.kt new file mode 100644 index 0000000..7d7ba29 --- /dev/null +++ b/app/src/main/java/com/bulletin/FormRecyclerViewAdapter.kt @@ -0,0 +1,119 @@ +package com.bulletin + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bulletin.models.BulletinItem +import com.bulletin.viewHolder.* +import com.example.bulletin.databinding.* + + +class FormRecyclerViewAdapter(var formSection: List,var listener: OnItemClickListener) : + RecyclerView.Adapter>() { + + + fun setRecyclerViewItems(formData: List) { + formSection = formData + notifyDataSetChanged() + } + + // region RecyclerView Adapter Methods + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + + // Based on the view type initilaize the viewholder + when(viewType) { + ITEM_VIEW_TYPE_TITLE -> { + val view = + LayoutFormSectionTitleBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionTitleViewHolder(view,listener) as BaseViewHolder + } + ITEM_VIEW_TYPE_MESSAGE -> { + val view = + LayoutFormSectionMessageBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionMessageViewHolder(view,listener) as BaseViewHolder + } + ITEM_VIEW_TYPE_MEDIA -> { + val view = + LayoutFormSectionMediaBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionMediaViewHolder(view,listener) as BaseViewHolder + } + ITEM_VIEW_TYPE_ACTION_BUTTON -> { + val view = + LayoutFormSectionActionButtonBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionActionButtonViewHolder(view,listener) as BaseViewHolder + } + ITEM_VIEW_TYPE_BULLET_POINT -> { + val view = + LayoutFormBulletPointBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionBulletPointViewHolder(view,listener) as BaseViewHolder + } + else -> { + val view = + LayoutFormSectionTitleBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FormSectionTitleViewHolder(view,listener) as BaseViewHolder + } + } + } + + override fun getItemCount(): Int { + // Item Count + return formSection.size ?: 0 + } + + override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { + // Bind the viewholder + holder.bind(formSection[position]) + } + + override fun getItemViewType(position: Int): Int { + + val item = formSection[position].also { } + +// return if (item is Title) { +// ITEM_VIEW_TYPE_TITLE +// } else if (item is Message) { +// ITEM_VIEW_TYPE_MESSAGE +// } else if (item is Media) { +// ITEM_VIEW_TYPE_MEDIA +// } else if (item is BulletPoint) { +// ITEM_VIEW_TYPE_BULLET_POINT +// } else if (item is ActionButton) { +// ITEM_VIEW_TYPE_ACTION_BUTTON +// } else { +// ITEM_VIEW_TYPE_TITLE +// } + + return when (item.type){ + BulletinItem.ItemType.UNDEFINED -> ITEM_VIEW_TYPE_TITLE + BulletinItem.ItemType.TITLE -> ITEM_VIEW_TYPE_TITLE + BulletinItem.ItemType.MESSAGE -> ITEM_VIEW_TYPE_MESSAGE + BulletinItem.ItemType.MEDIA -> ITEM_VIEW_TYPE_MEDIA + BulletinItem.ItemType.BULLET_POINT -> ITEM_VIEW_TYPE_BULLET_POINT + BulletinItem.ItemType.ACTION_BUTTON -> ITEM_VIEW_TYPE_ACTION_BUTTON + } + } + // endregion + + // region Constant Value For Adapter Class + companion object { + private const val ITEM_VIEW_TYPE_TITLE = 0 + private const val ITEM_VIEW_TYPE_MESSAGE = 1 + private const val ITEM_VIEW_TYPE_MEDIA = 2 + private const val ITEM_VIEW_TYPE_BULLET_POINT = 3 + private const val ITEM_VIEW_TYPE_ACTION_BUTTON = 4 + } + // endregion + + // region Methods +// fun setListener(context : OnItemClickListener){ +// listener = context +// } + + // endregion + + // region Interface Methods + interface OnItemClickListener { + fun formDidTriggerEvent(eventType: BulletinItem.EventType, baseItem : BulletinItem, index : Int) : Boolean + } + // endregion +} diff --git a/app/src/main/java/com/bulletin/extension/ImageExtension.kt b/app/src/main/java/com/bulletin/extension/ImageExtension.kt new file mode 100644 index 0000000..bba0a6f --- /dev/null +++ b/app/src/main/java/com/bulletin/extension/ImageExtension.kt @@ -0,0 +1,27 @@ +package com.bulletin.extension + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.widget.ImageView +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.load.Transformation +import com.bumptech.glide.request.target.CustomTarget +import com.example.bulletin.R + + +fun ImageView.loadImageWithUrl( + context: Context, + url: String, + transform: Transformation?, + completion: CustomTarget +) { + var builder: RequestBuilder = Glide.with(context) + .load(url) + .error(R.drawable.image_loading_bg) + if (transform != null) { + builder = builder.transform(transform) + } + builder.into(completion) +} diff --git a/app/src/main/java/com/bulletin/extension/Storage.kt b/app/src/main/java/com/bulletin/extension/Storage.kt new file mode 100644 index 0000000..821a023 --- /dev/null +++ b/app/src/main/java/com/bulletin/extension/Storage.kt @@ -0,0 +1,22 @@ +package com.bulletin.extension + +import android.content.SharedPreferences +import com.bulletin.models.Version +import com.bulletin.utilities.AppStorageHelper.edit + +private const val SHARED_PREFS_PARAMS_LATEST_APP_VERSION = "latest_app_version" + +var SharedPreferences.lastSeenVersion: Version? + set(newValue) { + edit { + if (newValue == null) { + it.remove(SHARED_PREFS_PARAMS_LATEST_APP_VERSION) + } else { + it.putString(SHARED_PREFS_PARAMS_LATEST_APP_VERSION, newValue.version.toString()) + } + } + } + get() { + val versionString = getString(SHARED_PREFS_PARAMS_LATEST_APP_VERSION, null) ?: return null + return Version(versionString) + } diff --git a/app/src/main/java/com/bulletin/extension/StringCompare.kt b/app/src/main/java/com/bulletin/extension/StringCompare.kt new file mode 100644 index 0000000..0d2dedd --- /dev/null +++ b/app/src/main/java/com/bulletin/extension/StringCompare.kt @@ -0,0 +1,28 @@ +package com.bulletin.extension + + +fun String.isNumeric(): Boolean { + if (this.isEmpty()) { + return false + } + val e = this.takeIf { it.isNotEmpty() } ?: return false + this.toUIntOrNull()?.let { return true } ?: return false +} + +fun String.validVersion(): String? { + + // Convert String In to Array + val versionBlocks = this.split(".").toTypedArray() + + // Validation + if (versionBlocks.size == 0) return null + + // Validation For String as Int + for (versionBlock in versionBlocks) { + if (versionBlock.isNumeric() == false) { + return null + } + } + + return versionBlocks.joinToString(".") +} diff --git a/app/src/main/java/com/bulletin/extension/StringExtension.kt b/app/src/main/java/com/bulletin/extension/StringExtension.kt new file mode 100644 index 0000000..30d1ac2 --- /dev/null +++ b/app/src/main/java/com/bulletin/extension/StringExtension.kt @@ -0,0 +1,49 @@ +package com.bulletin.extension + +import java.util.* + +fun String?.isEmpty(): Boolean { + return this == null || "" == trim() +} + +fun String?.capitalized(): String? { + if (this.isNullOrBlank()) { + return this + } + + return this.trim().split("\\s+".toRegex()) + .joinToString(" ") { it.replaceFirstChar { // it: Char + it.uppercase() + } } +} + +fun String?.toCamelCaseSingleWord(): String { + if (this == null) return "" + + var s = "" + if (length > 0) { + s = substring(0, 1).uppercase(Locale.getDefault()) + } + + if (length > 1) { + s += substring(1).lowercase(Locale.getDefault()) + } + return s +} + +fun String.toCamelCaseMultipleWords(): String { + if (length == 0) { + return this + } + val parts = split(" ").toTypedArray() + var camelCaseString = "" + for (part in parts) { + camelCaseString = camelCaseString + toProperCase(part) + " " + } + return camelCaseString +} + +private fun toProperCase(s: String): String { + return s.substring(0, 1).uppercase(Locale.getDefault()) + + s.substring(1).lowercase(Locale.getDefault()) +} diff --git a/app/src/main/java/com/bulletin/extension/TextAppearenceExtension.kt b/app/src/main/java/com/bulletin/extension/TextAppearenceExtension.kt new file mode 100644 index 0000000..facf982 --- /dev/null +++ b/app/src/main/java/com/bulletin/extension/TextAppearenceExtension.kt @@ -0,0 +1,15 @@ +package com.bulletin.extension + +import android.os.Build +import android.widget.TextView +import androidx.annotation.StyleRes + + +fun TextView.textAppearence(@StyleRes resId : Int) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + this.setTextAppearance(resId) + } else { + this.setTextAppearance(this.context, resId) + } +} + diff --git a/app/src/main/java/com/bulletin/models/ActionButton.kt b/app/src/main/java/com/bulletin/models/ActionButton.kt new file mode 100644 index 0000000..70d90af --- /dev/null +++ b/app/src/main/java/com/bulletin/models/ActionButton.kt @@ -0,0 +1,24 @@ +package com.bulletin.models + + +data class ActionButton(val title: String?, var clickPayload: Any?) : BulletinItem() { + + // region Init Methods + init { + type = ItemType.ACTION_BUTTON + } + + companion object { + + fun init(attributes: Map): ActionButton? { + + // Set Title + val title = (attributes["title"] as? String) ?: return null + + // Set Click Payload + val clickPayload = attributes["clickPayload"] + + return ActionButton(title, clickPayload) + } + } +} diff --git a/app/src/main/java/com/bulletin/models/BulletPoint.kt b/app/src/main/java/com/bulletin/models/BulletPoint.kt new file mode 100644 index 0000000..d0c9d39 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/BulletPoint.kt @@ -0,0 +1,81 @@ +package com.bulletin.models + +data class BulletPoint(var bullet: Bullet?, var titleText: String?, var subTitleText: String?) : + BulletinItem() { + + // region Init Methods + init { + type = ItemType.BULLET_POINT + } + + companion object { + + @Suppress("UNCHECKED_CAST") + fun init(attributes: Map): BulletPoint? { + + // Set Bullet + val bulletObj = attributes["bullet"] as? Map ?: return null + + val bullet = Bullet.init(bulletObj) ?: return null + + // Set Title Text + val titleText = (attributes["titleText"] as? String) ?: return null + + // Set SubTitle Text + val subTitleText = (attributes["subTitleText"] as? String) ?: return null + + return BulletPoint(bullet, titleText, subTitleText) + } + } +} + +data class Bullet(val bulletType: BulletType?, val unicode: String?, val imageUrl: String?) : + BulletinItem() { + + enum class BulletType { + UNICODE, + IMAGE; + } + + // region Init Methods + + + companion object { + + fun init(attributes: Map?): Bullet? { + + // Validation + val attributesObj = attributes ?: return null + + // Set BulletType + val bulletTypeString = (attributes["bulletType"] as? String) ?: return null + + // Set BulletType + val bulletType = (BulletType.valueOf(bulletTypeString.uppercase())) + + var visualSymbol = "" + var imageUrlString = "" + + when (bulletType) { + BulletType.UNICODE -> { + + // Set Unicode + visualSymbol = attributes["unicode"] as? String ?: return null + } + BulletType.IMAGE -> { + + // Set ImageUrl + imageUrlString = attributes["imageUrl"] as? String ?: return null + + } + else -> { + return null + } + } + + return Bullet(bulletType, visualSymbol, imageUrlString) + + } + } + +} diff --git a/app/src/main/java/com/bulletin/models/BulletinInfo.kt b/app/src/main/java/com/bulletin/models/BulletinInfo.kt new file mode 100644 index 0000000..2f5f9a1 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/BulletinInfo.kt @@ -0,0 +1,19 @@ +package com.bulletin.models + +import com.bulletin.utilities.VersionUtil +import java.io.Serializable + +class BulletinInfo(var version: Version, var items: List) : Serializable { + + companion object { + fun init(version: Version, items: MutableList): BulletinInfo { + return BulletinInfo(version, items) + } + + var descendingSort: Comparator = + Comparator { t2: BulletinInfo, t1: BulletinInfo -> + VersionUtil.versionCompare(t1.version.version, t2.version.version) + } + } + +} diff --git a/app/src/main/java/com/bulletin/models/BulletinItem.kt b/app/src/main/java/com/bulletin/models/BulletinItem.kt new file mode 100644 index 0000000..6e6c6fa --- /dev/null +++ b/app/src/main/java/com/bulletin/models/BulletinItem.kt @@ -0,0 +1,69 @@ +package com.bulletin.models + +import com.bulletin.utilities.RuntimeTypeAdapterFactory +import com.wrx.wazirx.views.bulletin.model.Media +import java.io.Serializable + +abstract class BulletinItem() : Serializable { + + // MARK: - Declarations + enum class ItemType(val value: String) { + UNDEFINED("Undefined"), + TITLE("title"), + MESSAGE("message"), + MEDIA("media"), + BULLET_POINT("bulletPoint"), + ACTION_BUTTON("actionButton"), + } + + enum class EventType(val value: String) { + TRIGGER_ACTION("triggerAppAction"), + } + + // MARK: - Variables + var type: ItemType = ItemType.UNDEFINED + + companion object { + val runtimeTypeAdapterFactory: RuntimeTypeAdapterFactory<*> + get() { + val mediaRuntimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of( + BulletinItem::class.java, "type" + ) + mediaRuntimeTypeAdapterFactory.registerSubtype(Title::class.java, "title") + mediaRuntimeTypeAdapterFactory.registerSubtype(Message::class.java, "message") + mediaRuntimeTypeAdapterFactory.registerSubtype(Media::class.java, "media") + mediaRuntimeTypeAdapterFactory.registerSubtype( + BulletPoint::class.java, + "bulletPoint" + ) + mediaRuntimeTypeAdapterFactory.registerSubtype( + ActionButton::class.java, + "actionButton" + ) + return mediaRuntimeTypeAdapterFactory + } + + // It Will Return Action Card Creatd With Proper Classes + fun createBulletinItem(attributes: Map?): BulletinItem? { + + // Validation + val attributes = attributes ?: return null + + // Validations + val typeString = attributes["type"] as? String ?: return null + val itemType = ItemType.valueOf(typeString) ?: return null + if (itemType != ItemType.UNDEFINED) { + return null + } + + // Get Bulletin Item +// itemType.classFromString() as? BulletinItem.ItemType { +// return bulletinItem.init(attributes: attributes) +// } + return null + } + + } + + //endregion +} diff --git a/app/src/main/java/com/bulletin/models/Media.kt b/app/src/main/java/com/bulletin/models/Media.kt new file mode 100644 index 0000000..c667729 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/Media.kt @@ -0,0 +1,54 @@ +package com.wrx.wazirx.views.bulletin.model + +import android.util.Size +import com.bulletin.models.BulletinItem +import com.bulletin.utilities.RuntimeTypeAdapterFactory + + +data class Media(var mediaType: MediaType = MediaType.IMAGE, val url: String?, val size: Size?) : + BulletinItem() { + + // region Init Methods + init { + type = BulletinItem.ItemType.MEDIA + } + + enum class MediaType(val value: String) { + IMAGE("image"), + } + + companion object { + + val runtimeTypeAdapterFactory: RuntimeTypeAdapterFactory<*> + get() { + val mediaRuntimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of( + Media::class.java, "type" + ) + mediaRuntimeTypeAdapterFactory.registerSubtype(Media::class.java, "Image") + return mediaRuntimeTypeAdapterFactory + } + + fun init(attributes: Map): Media? { + // Set Media Type + val mediaTypeString = attributes["mediaType"] as? String + var mediaType = MediaType.IMAGE + if (!mediaTypeString.isNullOrEmpty()) { + (MediaType.valueOf(mediaTypeString.uppercase())).let { + mediaType = it + } + } + + // Set Url + val urlString = (attributes["url"] as? String) ?: return null + + var size: Size? = null + + // Set Size + val width = (attributes["width"] as? Float)?.toInt() + val height = (attributes["height"] as? Float)?.toInt() + size = width?.let { height?.let { it1 -> Size(it, it1) } } + + return Media(mediaType, urlString, size) + } + } +} diff --git a/app/src/main/java/com/bulletin/models/Message.kt b/app/src/main/java/com/bulletin/models/Message.kt new file mode 100644 index 0000000..33562e3 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/Message.kt @@ -0,0 +1,35 @@ +package com.bulletin.models + + +data class Message(var messageType: MessageType = MessageType.TEXT, val text: String?) : + BulletinItem() { + + enum class MessageType(type: String) { + HTML("html"), + TEXT("text"); + } + + // region Init Methods + init { + type = ItemType.MESSAGE + } + + companion object { + fun init(attributes: Map): Message? { + + // Set Message Type + var messageType = MessageType.TEXT + val messasgeTypeString = attributes["messageType"] as? String + if (!messasgeTypeString.isNullOrEmpty()) { + (MessageType.valueOf(messasgeTypeString.uppercase())).let { + messageType = it + } + } + + // Set Text + val text = (attributes["text"] as? String) ?: return null + + return Message(messageType, text) + } + } +} diff --git a/app/src/main/java/com/bulletin/models/Title.kt b/app/src/main/java/com/bulletin/models/Title.kt new file mode 100644 index 0000000..a1feff4 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/Title.kt @@ -0,0 +1,33 @@ +package com.bulletin.models + +import android.graphics.Color + + +data class Title(val preTitleText: String?,val preTitleTextColor: Int?, val titleText: String?, val subTitleText: String?) : BulletinItem() { + + // region Init Methods + init { + type = ItemType.TITLE + } + + companion object { + + fun init(attributes: Map): Title? { + + // Set PreTitle + val preTitleText = (attributes["preTitleText"] as? String) ?: return null + + // Set PreTitle Color + val preTitleTextColor = (attributes["preTitleTextColor"] as? String) ?: return null + val preTitleTextColor1 = Color.parseColor(preTitleTextColor) + + // Set Title + val titleText = (attributes["titleText"] as? String) ?: return null + + // Set SubTitle + val subTitleText = (attributes["subTitleText"] as? String) ?: return null + + return Title(preTitleText,preTitleTextColor1, titleText, subTitleText) + } + } +} diff --git a/app/src/main/java/com/bulletin/models/Version.kt b/app/src/main/java/com/bulletin/models/Version.kt new file mode 100644 index 0000000..31bf615 --- /dev/null +++ b/app/src/main/java/com/bulletin/models/Version.kt @@ -0,0 +1,19 @@ +package com.bulletin.models + +import com.bulletin.extension.validVersion +import java.io.Serializable + +data class Version(val version: String) : Serializable { + + companion object { + + fun init(version: String): Version? { + + // Set Title + val validVersion = version.validVersion() ?: return null + + return Version(validVersion) + } + } + +} diff --git a/app/src/main/java/com/bulletin/utilities/AppStorageHelper.kt b/app/src/main/java/com/bulletin/utilities/AppStorageHelper.kt new file mode 100644 index 0000000..ccd86ab --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/AppStorageHelper.kt @@ -0,0 +1,26 @@ +package com.bulletin.utilities + +import android.content.Context +import android.content.SharedPreferences +import com.bulletin.BulletinApp.Companion.applicationContext + +object AppStorageHelper { + + private const val SHARED_PREFS_NAME = "Bulletin_Shared_Prefs" + val shared: SharedPreferences = + applicationContext.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE) + + inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) { + val edit = edit() + operation(edit) + edit.apply() + } + + var SharedPreferences.clearValue + set(newValue) { + edit { + it.clear() + } + } + get() = run { } +} diff --git a/app/src/main/java/com/bulletin/utilities/AppUpdatedChecker.kt b/app/src/main/java/com/bulletin/utilities/AppUpdatedChecker.kt new file mode 100644 index 0000000..d7dc56e --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/AppUpdatedChecker.kt @@ -0,0 +1,42 @@ +package com.bulletin.utilities + +import com.bulletin.extension.lastSeenVersion + + +object AppUpdatedChecker { + + enum class AppRunningState(val value: Int) { + NORMAL(1), + FRESHINSTALL(2), + AFTERUPDATE(3); + } + + var appRunningState = AppRunningState.NORMAL + + + fun currentAppRunningState() { + + // Fetch Last Known App Version from User Defaults + val lastKnownAppVersion: String? = + AppStorageHelper.shared.lastSeenVersion?.version // get(LAST_KNOWN_APP_VERSION_KEY); + + // Fetch Current App Version + val currentAppVersion: String? = VersionUtil.getApplicationVersion() + appRunningState = if (lastKnownAppVersion != null) { + if (currentAppVersion == lastKnownAppVersion) { + + // App is running on Same Version + AppRunningState.NORMAL + } else { + + // App is running newer version then Last known App Version + AppRunningState.AFTERUPDATE + } + } else { + + // App Running After Fresh Install + AppRunningState.FRESHINSTALL + } + } + +} diff --git a/app/src/main/java/com/bulletin/utilities/DeviceUtils.kt b/app/src/main/java/com/bulletin/utilities/DeviceUtils.kt new file mode 100644 index 0000000..90c5488 --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/DeviceUtils.kt @@ -0,0 +1,65 @@ +package com.bulletin.utilities + +import android.content.Context +import android.util.DisplayMetrics + + +object DeviceUtil { + + /** + * This method converts dp unit to equivalent pixels, depending on device density. + * + * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels + * @return A float value to represent px equivalent to dp depending on device density + */ + fun convertDpToPixel(context: Context, dp: Float): Int { + val resources = context.resources + val metrics = resources.displayMetrics + return dp.toInt() * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT) + } + + /** + * This method converts device specific pixels to density independent pixels. + * + * @param px A value in px (pixels) unit. Which we need to convert into db + * @return A float value to represent dp equivalent to px value + */ + fun convertPixelsToDp(context: Context, px: Float): Float { + val resources = context.resources + val metrics = resources.displayMetrics + return px / (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT) + } + + /** + * This method converts sp unit to equivalent pixels, depending on device density. + * + * @param sp A value in sp (scale independent pixels) unit. Which we need to convert into pixels + * @return A float value to represent px equivalent to sp depending on device scale + */ + fun convertSpToPixel(context: Context, sp: Float): Int { + val scaledDensity = context.resources.displayMetrics.scaledDensity + return (sp * scaledDensity).toInt() + } + + /** + * This method converts device specific pixels to scale independent pixels. + * + * @param px A value in px (pixels) unit. Which we need to convert into db + * @return A float value to represent sp equivalent to px value + */ + fun convertPixelsToSp(context: Context, px: Float): Float { + val scaledDensity = context.resources.displayMetrics.scaledDensity + return px / scaledDensity + } + + fun getDensity(context: Context): String { + val density = context.resources.displayMetrics.density + return if (density <= 1.0f) { + "1x" + } else if (density > 1.0f && density <= 2.0f) { + "2x" + } else { + "3x" + } + } +} diff --git a/app/src/main/java/com/bulletin/utilities/GsonHelper.kt b/app/src/main/java/com/bulletin/utilities/GsonHelper.kt new file mode 100644 index 0000000..8fe3ec0 --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/GsonHelper.kt @@ -0,0 +1,28 @@ +package com.bulletin.utilities + +import com.bulletin.models.BulletinItem +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.wrx.wazirx.views.bulletin.model.Media + +object GsonHelper { + + private val gsonBuilder: GsonBuilder by lazy { + val _gsonBuilder = GsonBuilder() + _gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ss+Z") + _gsonBuilder.enableComplexMapKeySerialization() + setupGsonBuilder(_gsonBuilder) + _gsonBuilder + } + + val gsonInstance: Gson by lazy { + gsonBuilder.create() + } + + private fun setupGsonBuilder(gsonBuilder: GsonBuilder) { + + gsonBuilder.registerTypeAdapterFactory(Media.runtimeTypeAdapterFactory) + gsonBuilder.registerTypeAdapterFactory(BulletinItem.runtimeTypeAdapterFactory) + } + +} diff --git a/app/src/main/java/com/bulletin/utilities/RuntimeTypeAdapterFactory.kt b/app/src/main/java/com/bulletin/utilities/RuntimeTypeAdapterFactory.kt new file mode 100644 index 0000000..824b49f --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/RuntimeTypeAdapterFactory.kt @@ -0,0 +1,223 @@ +package com.bulletin.utilities + + +import com.google.gson.* +import com.google.gson.internal.Streams +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import java.io.IOException + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   `abstract class Shape {
+ * int x;
+ * int y;
+ * }
+ * class Circle extends Shape {
+ * int radius;
+ * }
+ * class Rectangle extends Shape {
+ * int width;
+ * int height;
+ * }
+ * class Diamond extends Shape {
+ * int width;
+ * int height;
+ * }
+ * class Drawing {
+ * Shape bottomShape;
+ * Shape topShape;
+ * }
+`
* + * + * Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?
   `{
+ * "bottomShape": {
+ * "width": 10,
+ * "height": 5,
+ * "x": 0,
+ * "y": 0
+ * },
+ * "topShape": {
+ * "radius": 2,
+ * "x": 4,
+ * "y": 1
+ * }
+ * }`
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   `{
+ * "bottomShape": {
+ * "type": "Diamond",
+ * "width": 10,
+ * "height": 5,
+ * "x": 0,
+ * "y": 0
+ * },
+ * "topShape": {
+ * "type": "Circle",
+ * "radius": 2,
+ * "x": 4,
+ * "y": 1
+ * }
+ * }`
+ * Both the type field name (`"type"`) and the type labels (`"Rectangle"`) are configurable. + * + * + *

Registering Types

+ * Create a `RuntimeTypeAdapterFactory` by passing the base type and type field + * name to the [.of] factory method. If you don't supply an explicit type + * field name, `"type"` will be used.
   `RuntimeTypeAdapterFactory shapeAdapterFactory
+ * = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+`
* + * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   `shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
+ * shapeAdapter.registerSubtype(Circle.class, "Circle");
+ * shapeAdapter.registerSubtype(Diamond.class, "Diamond");
+`
* + * Finally, register the type adapter factory in your application's GSON builder: + *
   `Gson gson = new GsonBuilder()
+ * .registerTypeAdapterFactory(shapeAdapterFactory)
+ * .create();
+`
* + * Like `GsonBuilder`, this API supports chaining:
   `RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ * .registerSubtype(Rectangle.class)
+ * .registerSubtype(Circle.class)
+ * .registerSubtype(Diamond.class);
+`
* + */ +class RuntimeTypeAdapterFactory private constructor( + baseType: Class<*>?, + typeFieldName: String? +) : TypeAdapterFactory { + private val baseType: Class<*> + private var defaultTypeLabel: String? = null + private val typeFieldName: String + private val labelToSubtype: MutableMap> = LinkedHashMap() + /** + * Registers `type` identified by `label`. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either `type` or `label` + * have already been registered on this type adapter. + */ + /** + * Registers `type` identified by its [simple][Class.getSimpleName]. Labels are case sensitive. + * + * @throws IllegalArgumentException if either `type` or its simple name + * have already been registered on this type adapter. + */ + @JvmOverloads + fun registerSubtype( + type: Class?, + label: String? = type!!.simpleName + ): RuntimeTypeAdapterFactory { + if (type == null || label == null) { + throw NullPointerException() + } + labelToSubtype[label] = type + return this + } + + /** + * Registers `defaultType` which is used when the type is null or unknown + * You must call this method if you want to handle the cases where you expect the type to be null. + * If this method is not called then JsonParseException will be thrown if any null type is encountered. + */ + fun registerDefaultSubtype(type: Class?, label: String?): RuntimeTypeAdapterFactory { + if (type == null || label == null) { + throw NullPointerException() + } + defaultTypeLabel = label + registerSubtype(type, label) + return this + } + + override fun create(gson: Gson, type: TypeToken): TypeAdapter? { + if (type.rawType != baseType) { + return null + } + val labelToDelegate: MutableMap> = LinkedHashMap() + val subtypeToDelegate: MutableMap, TypeAdapter<*>> = LinkedHashMap() + for ((key, value) in labelToSubtype) { + val delegate = gson.getDelegateAdapter(this, TypeToken.get(value)) + labelToDelegate[key] = delegate + subtypeToDelegate[value] = delegate + } + return object : TypeAdapter() { + @Throws(IOException::class) + override fun read(`in`: JsonReader): R { + val jsonElement = Streams.parse(`in`) + val labelJsonElement = jsonElement.asJsonObject[typeFieldName] + val label: String + label = if (labelJsonElement == null) ({ + if (defaultTypeLabel == null) { + throw JsonParseException( + "cannot deserialize " + baseType + + " because it does not define a default " + typeFieldName + ) + } else { + defaultTypeLabel + } + + }).toString() else { + labelJsonElement.asString + } + + var delegate// registration requires that subtype extends T + = labelToDelegate[label] as TypeAdapter? + if (delegate == null) { + delegate = labelToDelegate[defaultTypeLabel] as TypeAdapter? + } + return delegate!!.fromJsonTree(jsonElement) + } + + @Throws(IOException::class) + override fun write(out: JsonWriter, value: R) { + val srcType: Class<*> = value!!::class.java + val delegate// registration requires that subtype extends T + = subtypeToDelegate[srcType] as TypeAdapter? + ?: throw JsonParseException( + "cannot serialize " + srcType.name + + "; did you forget to register a subtype?" + ) + val jsonObject = delegate.toJsonTree(value).asJsonObject + val clone = JsonObject() + for ((key, value1) in jsonObject.entrySet()) { + clone.add(key, value1) + } + Streams.write(clone, out) + } + }.nullSafe() + } + + companion object { + /** + * Creates a new runtime type adapter using for `baseType` using `typeFieldName` as the type field name. Type field names are case sensitive. + */ + fun of(baseType: Class?, typeFieldName: String?): RuntimeTypeAdapterFactory { + return RuntimeTypeAdapterFactory(baseType, typeFieldName) + } + + /** + * Creates a new runtime type adapter for `baseType` using `"type"` as + * the type field name. + */ + fun of(baseType: Class?): RuntimeTypeAdapterFactory { + return RuntimeTypeAdapterFactory(baseType, "type") + } + } + + init { + if (typeFieldName == null || baseType == null) { + throw NullPointerException() + } + this.baseType = baseType + this.typeFieldName = typeFieldName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bulletin/utilities/ThemeUtils.kt b/app/src/main/java/com/bulletin/utilities/ThemeUtils.kt new file mode 100644 index 0000000..69c93fa --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/ThemeUtils.kt @@ -0,0 +1,29 @@ +package com.bulletin.utilities + +import android.content.Context +import android.graphics.drawable.GradientDrawable +import android.util.TypedValue +import android.view.View +import androidx.annotation.AttrRes +import androidx.annotation.ColorInt + + +object ThemeUtils { + @ColorInt + fun getAttributedColor(@AttrRes attr: Int, context: Context): Int { + val value = TypedValue() + context.theme.resolveAttribute(attr, value, true) + return value.data + } + + fun applyThemeDrawable(view: View, @AttrRes attr: Int) { + val color = getAttributedColor(attr, view.context) + if (color != 0) { + val drawable = view.background + if (drawable is GradientDrawable) { + drawable.setColor(color) + } + view.setBackgroundDrawable(drawable) + } + } +} diff --git a/app/src/main/java/com/bulletin/utilities/VersionUtil.kt b/app/src/main/java/com/bulletin/utilities/VersionUtil.kt new file mode 100644 index 0000000..d1ecca4 --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/VersionUtil.kt @@ -0,0 +1,91 @@ +package com.bulletin.utilities + +import android.content.pm.PackageManager +import com.bulletin.BulletinApp +import com.bulletin.extension.isEmpty + +object VersionUtil { + + /** + * if v1>v2 : returns 1 + * if v1 vnum2) return 1 + + if (vnum2 > vnum1) return -1 + + // if equal, reset variables and + // go for next numeric part + vnum2 = 0 + vnum1 = vnum2 + i++ + j++ + } + return 0 + } + + fun getLatestVersion(v1: String?, v2: String?): String? { + if (v1.isEmpty()) return v2 + if (v2.isEmpty()) return v1 + + // if (v1!=null && v2!=null) call versionCompare + return if (v1?.let { v2?.let { it1 -> versionCompare(it, it1) } } == -1) { + v2 + } else { + v1 + } + } + + fun getApplicationVersion(): String? { + try { + val pInfo = + BulletinApp.shared.packageManager.getPackageInfo(BulletinApp.shared.packageName, 0) + return pInfo.versionName + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + return "" + } + + fun getVersionInAscendingOrder(set: MutableSet): List { + val list: List = set.toList() + return list.sortedWith { version, version1 -> versionCompare(version1, version) }; + } + +} diff --git a/app/src/main/java/com/bulletin/utilities/ViewUtil.kt b/app/src/main/java/com/bulletin/utilities/ViewUtil.kt new file mode 100644 index 0000000..4132216 --- /dev/null +++ b/app/src/main/java/com/bulletin/utilities/ViewUtil.kt @@ -0,0 +1,89 @@ +package com.bulletin.utilities + +import android.annotation.SuppressLint +import android.view.MotionEvent +import android.view.View +import android.view.animation.Animation +import android.view.animation.DecelerateInterpolator +import android.view.animation.ScaleAnimation + + +object ViewUtil { + + @SuppressLint("ClickableViewAccessibility") + fun addBounceEffect(view: View) { + view.setOnTouchListener { v: View, event: MotionEvent -> + onButtonTouch( + v, + event + ) + } + } + + private fun onButtonTouch(button: View, event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_DOWN) { + onButtonPressed(button) + return true + } else if (event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_OUTSIDE) { + onButtonReleased(button) + } + + // Handle click event + if (event.action == MotionEvent.ACTION_UP) { + button.performClick() + } + return false + } + + private fun onButtonTouchListener( + button: View, + event: MotionEvent, + touchListener: TouchListener + ): Boolean { + if (event.action == MotionEvent.ACTION_DOWN) { + // onButtonPressed(button); + touchListener.onButtonPressed() + return true + } else if (event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_OUTSIDE) { + // onButtonReleased(button); + touchListener.onButtonReleased() + } + + // Handle click event + if (event.action == MotionEvent.ACTION_UP) { + button.performClick() + } + return false + } + + fun onButtonPressed(button: View) { + val scaleAnimation = ScaleAnimation( + 1f, 0.9f, + 1f, 0.9f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f + ) + scaleAnimation.interpolator = DecelerateInterpolator() + scaleAnimation.duration = 100 + scaleAnimation.fillAfter = true + button.startAnimation(scaleAnimation) + } + + fun onButtonReleased(button: View) { + val scaleAnimation = ScaleAnimation( + 0.9f, 1f, + 0.9f, 1f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f + ) + scaleAnimation.interpolator = DecelerateInterpolator() + scaleAnimation.duration = 100 + scaleAnimation.fillAfter = true + button.startAnimation(scaleAnimation) + } + + interface TouchListener { + fun onButtonPressed() + fun onButtonReleased() + } +} diff --git a/app/src/main/java/com/bulletin/viewHolder/BaseViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/BaseViewHolder.kt new file mode 100644 index 0000000..4ba4297 --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/BaseViewHolder.kt @@ -0,0 +1,42 @@ +package com.bulletin.viewHolder + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.models.BulletinItem + + +abstract class BaseViewHolder( + VB: ViewBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : RecyclerView.ViewHolder(VB.root) { + + var _listener: FormRecyclerViewAdapter.OnItemClickListener? = null + + /** The view binding instance. */ + protected var _binding: ViewBinding? = null + protected var topCellSeparatorView: View? = null + protected var bottomCellSeparatorView: View? = null + protected var bgView: View? = null + lateinit var baseItem: T + + init { + _listener = listener + _binding = VB + } + + // MARK: - Override Methods + open fun updateAppearance() { + + } + + // region Abstract Method + open fun bind(item: T) { + baseItem = item + updateAppearance() + } + + abstract fun getBackgroundView(): View? + // endregion +} diff --git a/app/src/main/java/com/bulletin/viewHolder/FormSectionActionButtonViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/FormSectionActionButtonViewHolder.kt new file mode 100644 index 0000000..e07cfe7 --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/FormSectionActionButtonViewHolder.kt @@ -0,0 +1,83 @@ +package com.bulletin.viewHolder + +import android.content.res.ColorStateList +import android.view.View +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.textAppearence +import com.bulletin.models.ActionButton +import com.bulletin.models.BulletinItem +import com.bulletin.utilities.DeviceUtil +import com.bulletin.utilities.ThemeUtils +import com.bulletin.utilities.ViewUtil +import com.example.bulletin.R +import com.example.bulletin.databinding.LayoutFormSectionActionButtonBinding + + +class FormSectionActionButtonViewHolder( + val viewBinding: LayoutFormSectionActionButtonBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : + BaseViewHolder(viewBinding, listener) { + + // region Methods + override fun bind(item: ActionButton) { + super.bind(item) + + // Set Title + if (!item.title.isNullOrBlank()) { + viewBinding.actionButton.text = item.title + viewBinding.actionButton.setVisibility(View.VISIBLE) + } else { + viewBinding.actionButton.text = "" + viewBinding.actionButton.setVisibility(View.GONE) + } + + viewBinding.actionButton.setOnClickListener { + _listener?.formDidTriggerEvent( + BulletinItem.EventType.TRIGGER_ACTION, + item, + adapterPosition + ) + } + + ViewUtil.addBounceEffect(viewBinding.actionButton) + + } + + override fun getBackgroundView(): View? { + return null + } + + override fun updateAppearance() { + super.updateAppearance() + + viewBinding.actionButton.textAppearence(R.style.base_semi_bold) + + viewBinding.actionButton.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.brand_text_primary, + viewBinding.actionButton.context + ) + ) + viewBinding.actionButton.setBackgroundColor( + ThemeUtils.getAttributedColor( + R.attr.main_bg_surface_alt, + viewBinding.actionButton.context + ) + ) + + viewBinding.actionButton.strokeWidth = + DeviceUtil.convertDpToPixel(viewBinding.actionButton.context, 1f) + viewBinding.actionButton.setStrokeColor( + ColorStateList.valueOf( + ThemeUtils.getAttributedColor( + R.attr.brand_bg_primary, + viewBinding.actionButton.context + ) + ) + ) + + } + // endregion + +} diff --git a/app/src/main/java/com/bulletin/viewHolder/FormSectionBulletPointViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/FormSectionBulletPointViewHolder.kt new file mode 100644 index 0000000..cedfaa5 --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/FormSectionBulletPointViewHolder.kt @@ -0,0 +1,128 @@ +package com.bulletin.viewHolder + +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.view.View +import androidx.core.text.HtmlCompat +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.loadImageWithUrl +import com.bulletin.extension.textAppearence +import com.bulletin.models.Bullet +import com.bulletin.models.BulletPoint +import com.bulletin.utilities.ThemeUtils +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.example.bulletin.R +import com.example.bulletin.databinding.LayoutFormBulletPointBinding + + +class FormSectionBulletPointViewHolder( + val viewBinding: LayoutFormBulletPointBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : + BaseViewHolder(viewBinding, listener) { + + // region Methods + override fun bind(item: BulletPoint) { + super.bind(item) + + viewBinding.bulletImageView.setVisibility(View.GONE) + viewBinding.bulletLabel.setVisibility(View.GONE) + + when (item.bullet?.bulletType) { + Bullet.BulletType.UNICODE -> { + + val unicode = item.bullet?.unicode + if (!unicode.isNullOrBlank()) { + val fromHtml = HtmlCompat.fromHtml(unicode, HtmlCompat.FROM_HTML_MODE_COMPACT) + viewBinding.bulletLabel.text = fromHtml + viewBinding.bulletLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.bulletLabel.text = "" + viewBinding.bulletLabel.setVisibility(View.GONE) + } + + } + Bullet.BulletType.IMAGE -> { + (item.bullet?.imageUrl)?.let { + + viewBinding.bulletImageView.loadImageWithUrl( + viewBinding.bulletImageView.getContext(), + it, + null, + object : CustomTarget() { + + override fun onResourceReady( + resource: Drawable, + transition: Transition? + ) { + val bitmap = (resource as BitmapDrawable).bitmap + viewBinding.bulletImageView.setImageBitmap(bitmap) + viewBinding.bulletLabel.setVisibility(View.GONE) + viewBinding.bulletImageView.setVisibility(View.VISIBLE) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + print("onLoadFailed") + } + + override fun onLoadCleared(placeholder: Drawable?) { + print("onLoadCleared") + } + + }) + } + } + else -> { + + } + } + + // Set Pre Title + if (!item.titleText.isNullOrBlank()) { + viewBinding.titleLabel.text = item.titleText + viewBinding.titleLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.titleLabel.text = "" + viewBinding.titleLabel.setVisibility(View.GONE) + } + + // Set Title + if (!item.subTitleText.isNullOrBlank()) { + viewBinding.subtitleLabel.text = item.subTitleText + viewBinding.subtitleLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.subtitleLabel.text = "" + viewBinding.subtitleLabel.setVisibility(View.GONE) + } + + } + + override fun updateAppearance() { + super.updateAppearance() + + // Set Default Properties + viewBinding.titleLabel.textAppearence(R.style.large_semi_bold) + viewBinding.subtitleLabel.textAppearence(R.style.base_regular) + + viewBinding.titleLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.main_text_primary, + viewBinding.titleLabel.context + ) + ) + viewBinding.subtitleLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.main_text_secondary, + viewBinding.subtitleLabel.context + ) + ) + + } + + override fun getBackgroundView(): View? { + return null + } + // endregion + +} diff --git a/app/src/main/java/com/bulletin/viewHolder/FormSectionMediaViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/FormSectionMediaViewHolder.kt new file mode 100644 index 0000000..1afe615 --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/FormSectionMediaViewHolder.kt @@ -0,0 +1,72 @@ +package com.bulletin.viewHolder + +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.view.View +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.loadImageWithUrl +import com.bulletin.utilities.DeviceUtil +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.example.bulletin.databinding.LayoutFormSectionMediaBinding +import com.wrx.wazirx.views.bulletin.model.Media + + +class FormSectionMediaViewHolder( + val viewBinding: LayoutFormSectionMediaBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : + BaseViewHolder(viewBinding, listener) { + + // region Methods + override fun bind(item: Media) { + super.bind(item) + + // Set Image + viewBinding.bannerImageView.setVisibility(View.GONE) + + item.size?.let { + viewBinding.bannerImageView.layoutParams.width = DeviceUtil.convertPixelsToDp(viewBinding.bannerImageView.context,it.width.toFloat()).toInt() + viewBinding.bannerImageView.layoutParams.height = DeviceUtil.convertPixelsToDp(viewBinding.bannerImageView.context,it.height.toFloat()).toInt() + } + + (item.url)?.let { + + viewBinding.bannerImageView.loadImageWithUrl( + viewBinding.bannerImageView.getContext(), + it, + null, + object : CustomTarget() { + + override fun onResourceReady( + resource: Drawable, + transition: Transition? + ) { + val bitmap = (resource as BitmapDrawable).bitmap + viewBinding.bannerImageView.setImageBitmap(bitmap) + viewBinding.bannerImageView.setVisibility(View.VISIBLE) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + print("onLoadFailed") + } + + override fun onLoadCleared(placeholder: Drawable?) { + print("onLoadCleared") + } + + }) + } + + } + + override fun getBackgroundView(): View? { + return null + } + + override fun updateAppearance() { + super.updateAppearance() + } + // endregion + +} diff --git a/app/src/main/java/com/bulletin/viewHolder/FormSectionMessageViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/FormSectionMessageViewHolder.kt new file mode 100644 index 0000000..321039a --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/FormSectionMessageViewHolder.kt @@ -0,0 +1,74 @@ +package com.bulletin.viewHolder + +import android.view.View +import androidx.core.text.HtmlCompat +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.textAppearence +import com.bulletin.models.Message +import com.bulletin.utilities.ThemeUtils +import com.example.bulletin.R +import com.example.bulletin.databinding.LayoutFormSectionMessageBinding + + +class FormSectionMessageViewHolder( + val viewBinding: LayoutFormSectionMessageBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : + BaseViewHolder(viewBinding, listener) { + + // region Methods + override fun bind(item: Message) { + + super.bind(item) + + + when (item.messageType) { + Message.MessageType.HTML -> { + // Set Subttitle + if (!item.text.isNullOrBlank()) { + val fromHtml = HtmlCompat.fromHtml(item.text, HtmlCompat.FROM_HTML_MODE_COMPACT) + viewBinding.messageLabel.text = fromHtml + viewBinding.messageLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.messageLabel.text = "" + viewBinding.messageLabel.setVisibility(View.GONE) + } + } + Message.MessageType.TEXT -> { + // Set Subttitle + if (!item.text.isNullOrBlank()) { + viewBinding.messageLabel.text = item.text + viewBinding.messageLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.messageLabel.text = "" + viewBinding.messageLabel.setVisibility(View.GONE) + } + } + else -> { + viewBinding.messageLabel.text = "" + viewBinding.messageLabel.setVisibility(View.GONE) + } + } + + } + + override fun getBackgroundView(): View? { + return null + } + + override fun updateAppearance() { + super.updateAppearance() + + // Set Default Properties + viewBinding.messageLabel.textAppearence(R.style.base_regular) + + viewBinding.messageLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.main_text_primary, + viewBinding.messageLabel.context + ) + ) + } + // endregion + +} diff --git a/app/src/main/java/com/bulletin/viewHolder/FormSectionTitleViewHolder.kt b/app/src/main/java/com/bulletin/viewHolder/FormSectionTitleViewHolder.kt new file mode 100644 index 0000000..0b43637 --- /dev/null +++ b/app/src/main/java/com/bulletin/viewHolder/FormSectionTitleViewHolder.kt @@ -0,0 +1,90 @@ +package com.bulletin.viewHolder + +import android.os.Build +import android.view.View +import com.bulletin.FormRecyclerViewAdapter +import com.bulletin.extension.textAppearence +import com.bulletin.models.Title +import com.bulletin.utilities.ThemeUtils +import com.example.bulletin.R +import com.example.bulletin.databinding.LayoutFormSectionTitleBinding + + +class FormSectionTitleViewHolder( + val viewBinding: LayoutFormSectionTitleBinding, + listener: FormRecyclerViewAdapter.OnItemClickListener +) : + BaseViewHolder(viewBinding, listener) { + + // region Methods + override fun bind(item: Title) { + super.bind(item) + + itemView.setOnClickListener { + + } + + // Set App Title + if (!item.preTitleText.isNullOrBlank()) { + viewBinding.preTitleLabel.text = item.preTitleText + viewBinding.preTitleLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.preTitleLabel.text = "" + viewBinding.preTitleLabel.setVisibility(View.GONE) + } + + // Set App Version + if (!item.titleText.isNullOrBlank()) { + viewBinding.titleLabel.text = item.titleText + viewBinding.titleLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.titleLabel.text = "" + viewBinding.titleLabel.setVisibility(View.GONE) + } + + // Set App Version + if (!item.subTitleText.isNullOrBlank()) { + viewBinding.subtitleLabel.text = item.subTitleText + viewBinding.subtitleLabel.setVisibility(View.VISIBLE) + } else { + viewBinding.subtitleLabel.text = "" + viewBinding.subtitleLabel.setVisibility(View.GONE) + } + + } + + override fun getBackgroundView(): View? { + return null + } + + override fun updateAppearance() { + super.updateAppearance() + + // Set Default Properties + viewBinding.preTitleLabel.textAppearence(R.style.small_medium) + viewBinding.titleLabel.textAppearence(R.style.heading_4_semi_bold) + viewBinding.subtitleLabel.textAppearence(R.style.base_regular) + + viewBinding.preTitleLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.success_text_primary, + viewBinding.preTitleLabel.context + ) + ) + viewBinding.titleLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.main_text_primary, + viewBinding.titleLabel.context + ) + ) + viewBinding.subtitleLabel.setTextColor( + ThemeUtils.getAttributedColor( + R.attr.main_text_primary, + viewBinding.subtitleLabel.context + ) + ) + + } + // endregion + +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> + <aapt:attr name="android:fillColor"> + <gradient + android:endX="85.84757" + android:endY="92.4963" + android:startX="42.9492" + android:startY="49.59793" + android:type="linear"> + <item + android:color="#44000000" + android:offset="0.0" /> + <item + android:color="#00000000" + android:offset="1.0" /> + </gradient> + </aapt:attr> + </path> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> +</vector> \ No newline at end of file diff --git a/app/src/main/res/drawable/header_background.xml b/app/src/main/res/drawable/header_background.xml new file mode 100644 index 0000000..afbb247 --- /dev/null +++ b/app/src/main/res/drawable/header_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners + android:topLeftRadius="10dp" + android:topRightRadius="10dp" /> +</shape> diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:fillColor="#3DDC84" + android:pathData="M0,0h108v108h-108z" /> + <path + android:fillColor="#00000000" + android:pathData="M9,0L9,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,0L19,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M29,0L29,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M39,0L39,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M49,0L49,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M59,0L59,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M69,0L69,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M79,0L79,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M89,0L89,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M99,0L99,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,9L108,9" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,19L108,19" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,29L108,29" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,39L108,39" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,49L108,49" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,59L108,59" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,69L108,69" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,79L108,79" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,89L108,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,99L108,99" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,29L89,29" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,39L89,39" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,49L89,49" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,59L89,59" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,69L89,69" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,79L89,79" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M29,19L29,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M39,19L39,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M49,19L49,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M59,19L59,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M69,19L69,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M79,19L79,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> +</vector> diff --git a/app/src/main/res/drawable/image_loading_bg.xml b/app/src/main/res/drawable/image_loading_bg.xml new file mode 100644 index 0000000..0d0ca2b --- /dev/null +++ b/app/src/main/res/drawable/image_loading_bg.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="3dp" /> + <solid android:color="@color/transparent" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/view_background.xml b/app/src/main/res/drawable/view_background.xml new file mode 100644 index 0000000..783b849 --- /dev/null +++ b/app/src/main/res/drawable/view_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners + android:radius="10dp" /> +</shape> diff --git a/app/src/main/res/font/ibm_plex_sans_bold.ttf b/app/src/main/res/font/ibm_plex_sans_bold.ttf new file mode 100644 index 0000000..e5389d8 Binary files /dev/null and b/app/src/main/res/font/ibm_plex_sans_bold.ttf differ diff --git a/app/src/main/res/font/ibm_plex_sans_medium.ttf b/app/src/main/res/font/ibm_plex_sans_medium.ttf new file mode 100644 index 0000000..9395402 Binary files /dev/null and b/app/src/main/res/font/ibm_plex_sans_medium.ttf differ diff --git a/app/src/main/res/font/ibm_plex_sans_regular.ttf b/app/src/main/res/font/ibm_plex_sans_regular.ttf new file mode 100644 index 0000000..b581964 Binary files /dev/null and b/app/src/main/res/font/ibm_plex_sans_regular.ttf differ diff --git a/app/src/main/res/font/ibm_plex_sans_semi_bold.ttf b/app/src/main/res/font/ibm_plex_sans_semi_bold.ttf new file mode 100644 index 0000000..a5bd9ee Binary files /dev/null and b/app/src/main/res/font/ibm_plex_sans_semi_bold.ttf differ diff --git a/app/src/main/res/layout/bulletin_dialog.xml b/app/src/main/res/layout/bulletin_dialog.xml new file mode 100644 index 0000000..040f3e2 --- /dev/null +++ b/app/src/main/res/layout/bulletin_dialog.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="20dp" + tools:context=".BulletinDialog"> + + <LinearLayout + android:id="@+id/main_background_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/view_background" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + android:orientation="vertical"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/header_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/header_background" + android:paddingStart="20dp" + android:paddingTop="12dp" + android:paddingEnd="20dp" + android:paddingBottom="8dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/header_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:gravity="center" + android:text="@string/whats_new_title" + android:textSize="14sp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/list_view" + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintVertical_weight="1" + android:clipToPadding="false" + android:overScrollMode="never" + android:layout_weight="1" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/header_view" + app:layout_constraintVertical_chainStyle="spread"/> + + <Button + android:id="@+id/go_it_button" + style="@style/Widget.MaterialComponents.Button.UnelevatedButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="20dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="20dp" + android:layout_marginBottom="20dp" + android:insetTop="0dp" + android:insetBottom="0dp" + android:text="@string/okay_go_it" + android:textSize="14sp" + app:cornerRadius="5dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/list_view" + app:layout_constraintVertical_chainStyle="spread"/> + + </LinearLayout> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/layout_form_bullet_point.xml b/app/src/main/res/layout/layout_form_bullet_point.xml new file mode 100644 index 0000000..1d9d159 --- /dev/null +++ b/app/src/main/res/layout/layout_form_bullet_point.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/bullet_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="20dp" + android:layout_marginTop="17dp" + app:layout_constraintEnd_toStartOf="@+id/item_container" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/bullet_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Name" /> + + <ImageView + android:id="@+id/bullet_image_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Name" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/item_container" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="20dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/bullet_container" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/title_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textSize="14sp" + app:layout_constraintBottom_toTopOf="@id/subtitle_label" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Name" /> + + <TextView + android:id="@+id/subtitle_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:textSize="14sp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="@id/title_label" + app:layout_constraintTop_toBottomOf="@id/title_label" + tools:text="Subtitle" /> + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/layout_form_section_action_button.xml b/app/src/main/res/layout/layout_form_section_action_button.xml new file mode 100644 index 0000000..c98c027 --- /dev/null +++ b/app/src/main/res/layout/layout_form_section_action_button.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/action_button" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textAppearance="@style/TextStyle" + android:layout_marginTop="16dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" + android:layout_marginBottom="16dp" + android:textAllCaps="false" + android:insetTop="0dp" + android:insetRight="0dp" + android:insetBottom="0dp" + android:insetLeft="0dp" + android:textSize="18sp" + android:stateListAnimator="@null" + app:cornerRadius="4dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Create account" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/layout_form_section_media.xml b/app/src/main/res/layout/layout_form_section_media.xml new file mode 100644 index 0000000..e24d801 --- /dev/null +++ b/app/src/main/res/layout/layout_form_section_media.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/banner_image_view" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginLeft="20dp" + android:layout_marginTop="16dp" + android:layout_marginRight="20dp" + android:layout_marginBottom="0dp" + android:adjustViewBounds="true" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/layout_form_section_message.xml b/app/src/main/res/layout/layout_form_section_message.xml new file mode 100644 index 0000000..c2cc8ed --- /dev/null +++ b/app/src/main/res/layout/layout_form_section_message.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/message_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" + android:textSize="14sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Name" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/layout_form_section_title.xml b/app/src/main/res/layout/layout_form_section_title.xml new file mode 100644 index 0000000..3794581 --- /dev/null +++ b/app/src/main/res/layout/layout_form_section_title.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/item_background" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="20dp" + android:paddingTop="16dp" + android:paddingEnd="20dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/pre_title_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Name" /> + + <TextView + android:id="@+id/title_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textSize="22sp" + android:layout_gravity="start" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/pre_title_label" + tools:text="Daxesh Nagar Daxesh Nagar" /> + + <TextView + android:id="@+id/subtitle_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textSize="14sp" + android:layout_gravity="start" + android:layout_marginTop="16dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/title_label" + tools:text="Daxesh Nagar Daxesh Nagar" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_launcher_background" /> + <foreground android:drawable="@drawable/ic_launcher_foreground" /> +</adaptive-icon> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_launcher_background" /> + <foreground android:drawable="@drawable/ic_launcher_foreground" /> +</adaptive-icon> \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..86c04a6 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="purple_200">#FFBB86FC</color> + <color name="purple_500">#FF6200EE</color> + <color name="purple_700">#FF3700B3</color> + <color name="teal_200">#FF03DAC5</color> + <color name="teal_700">#FF018786</color> + <color name="black">#FF000000</color> + <color name="white">#FFFFFFFF</color> + + <color name="transparent">#00000000</color> + + <color name="colorPrimaryBackground">#18222C</color> + + ------------------ New Color ------------------------ + <color name="colors_black">#000000</color> + <color name="colors_white">#ffffff</color> + + <color name="colors_gray_10">#FBFCFE</color> + <color name="colors_gray_20">#F2F2F8</color> + <color name="colors_gray_30">#D9E1EB</color> + <color name="colors_gray_40">#A0AAB5</color> + <color name="colors_gray_50">#6F7F90</color> + <color name="colors_gray_60">#4C5C70</color> + <color name="colors_gray_70">#2E3E54</color> + <color name="colors_gray_80">#232F3F</color> + <color name="colors_gray_90">#212C3A</color> + <color name="colors_gray_100">#1A212B</color> + + <color name="colors_red_10">#FFEFEF</color> + <color name="colors_red_20">#fed7d7</color> + <color name="colors_red_30">#feb2b2</color> + <color name="colors_red_40">#fc8181</color> + <color name="colors_red_50">#f56565</color> + <color name="colors_red_60">#e53e3e</color> + <color name="colors_red_70">#c53030</color> + <color name="colors_red_80">#9b2c2c</color> + <color name="colors_red_90">#742a2a</color> + <color name="colors_red_100">#4B2830</color> + + <color name="colors_yellow_10">#fffff0</color> + <color name="colors_yellow_20">#fefcbf</color> + <color name="colors_yellow_30">#faf089</color> + <color name="colors_yellow_40">#f6e05e</color> + <color name="colors_yellow_50">#ecc94b</color> + <color name="colors_yellow_60">#d69e2e</color> + <color name="colors_yellow_70">#b7791f</color> + <color name="colors_yellow_80">#975a16</color> + <color name="colors_yellow_90">#744210</color> + <color name="colors_yellow_100">#4F3502</color> + + <color name="colors_green_10">#E0FAEE</color> + <color name="colors_green_20">#ABEDCF</color> + <color name="colors_green_30">#7BDBB0</color> + <color name="colors_green_40">#56C292</color> + <color name="colors_green_50">#3BA073</color> + <color name="colors_green_60">#287D57</color> + <color name="colors_green_70">#1D5E41</color> + <color name="colors_green_80">#16422E</color> + <color name="colors_green_90">#123023</color> + + <color name="colors_blue_10">#E8EEFD</color> + <color name="colors_blue_20">#B6C9FA</color> + <color name="colors_blue_30">#96B2F7</color> + <color name="colors_blue_40">#2DA4FE</color> + <color name="colors_blue_50">#167CF9</color> + <color name="colors_blue_60">#3067F0</color> + <color name="colors_blue_70">#1746BD</color> + <color name="colors_blue_80">#2A5573</color> + <color name="colors_blue_90">#19364A</color> + + <color name="colors_orange_10">#FDEFE9</color> + <color name="colors_orange_20">#FAE0D4</color> + <color name="colors_orange_30">#F6C4AD</color> + <color name="colors_orange_40">#F1A07B</color> + <color name="colors_orange_50">#EE895B</color> + <color name="colors_orange_60">#E86427</color> + <color name="colors_orange_70">#BF5728</color> + <color name="colors_orange_80">#964929</color> + <color name="colors_orange_90">#713D29</color> + <color name="colors_orange_100">#4B312A</color> + +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..3d45ab9 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ +<resources> + <string name="app_name">Bulletin</string> + + <string name="okay_go_it">OKay, Go it</string> + <string name="whats_new_title">What’s new in this update?</string> + + +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..0476db3 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,283 @@ +<resources xmlns:tools="http://schemas.android.com/tools"> + + <!-- <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />--> + + <!-- <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />--> + + <!-- <style name="TransactionDetailsDialog" parent="Theme.AppCompat.Light.NoActionBar">--> + <!-- <item name="windowNoTitle">true</item>--> + <!-- <item name="android:windowAnimationStyle">@style/TransactionDetailsDialog.Animation</item>--> + <!-- <item name="android:backgroundDimEnabled">true</item>--> + <!-- <item name="android:windowFullscreen">true</item>--> + <!-- <item name="android:windowIsFloating">false</item>--> + <!-- <item name="android:backgroundDimAmount">0.0</item>--> + <!-- </style>--> + <!-- <style name="Theme.Transparent" parent="Theme.MaterialComponents.DayNight.NoActionBar">--> + <!-- <item name="android:windowIsTranslucent">true</item>--> + <!-- <item name="android:windowFrame">@null</item>--> + <!-- <item name="android:windowFullscreen">true</item>--> + <!-- <item name="android:windowBackground">@android:color/transparent</item>--> + <!-- <item name="android:windowContentOverlay">@null</item>--> + <!-- <item name="android:windowNoTitle">true</item>--> + <!-- <item name="android:windowIsFloating">true</item>--> + <!-- <item name="android:backgroundDimEnabled">false</item>--> + <!-- <item name="android:windowAnimationStyle">@style/WDConfirmDialog.Animation</item>--> + <!-- </style>--> + + <style name="TextStyle" parent="@android:style/TextAppearance"> + <item name="android:textSize">20sp</item> + <item name="android:textColor">#aacbb4</item> + </style> + + <!-- <style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">--> + <!-- <item name="android:background">#33000000</item>--> + <!-- <item name="android:windowIsTranslucent">true</item>--> + <!-- <item name="android:windowFullscreen">true</item>--> + <!-- <item name="android:windowBackground">@android:color/transparent</item>--> + <!-- <item name="android:windowContentOverlay">@null</item>--> + <!-- <item name="android:windowNoTitle">true</item>--> + <!-- <item name="android:backgroundDimEnabled">false</item>--> + <!-- </style>--> + + <style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowFullscreen">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowNoTitle">true</item> + <item name="android:backgroundDimEnabled">false</item> + </style> + + <style name="SheetDialog" parent="Theme.Material3.Light.Dialog"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:colorBackground">@android:color/transparent</item> + <item name="android:backgroundDimEnabled">true</item> + <item name="android:backgroundDimAmount">0.3</item> + <item name="android:windowFrame">@null</item> + <item name="android:windowIsFloating">true</item> + </style> + + <!-- <style name="DialogStyle" parent="SheetDialog">--> + <!-- <item name="android:titleColor">@android:color/transparent</item>--> + <!-- <item name="android:subTitleColor">@android:color/transparent</item>--> + <!-- </style>--> + + <style name="default_button"> + <item name="android:insetTop">0dp</item> + <item name="android:insetBottom">0dp</item> + <item name="android:insetLeft">0dp</item> + <item name="android:insetRight">0dp</item> + </style> + + <style name="heading_1_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">48sp</item> + </style> + + <style name="heading_1_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">48sp</item> + </style> + + <style name="heading_1_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">48sp</item> + </style> + + <style name="heading_1_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">48sp</item> + </style> + + + <!--Heading 2--> + <style name="heading_2_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">32sp</item> + </style> + + <style name="heading_2_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">32sp</item> + </style> + + <style name="heading_2_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">32sp</item> + </style> + + <style name="heading_2_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">32sp</item> + </style> + + <!--Heading 3--> + <style name="heading_3_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">25sp</item> + </style> + + <style name="heading_3_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">25sp</item> + </style> + + <style name="heading_3_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">25sp</item> + </style> + + <style name="heading_3_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">25sp</item> + </style> + + <!--Heading 4--> + <style name="heading_4_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">22sp</item> + </style> + + <style name="heading_4_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">22sp</item> + </style> + + <style name="heading_4_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">22sp</item> + </style> + + <style name="heading_4_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">22sp</item> + </style> + + <!--Heading 5--> + <style name="heading_5_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">20sp</item> + </style> + + <style name="heading_5_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">20sp</item> + </style> + + <style name="heading_5_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">20sp</item> + </style> + + <style name="heading_5_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">20sp</item> + </style> + + <!--Heading 6--> + <style name="heading_6_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="heading_6_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="heading_6_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="heading_6_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">18sp</item> + </style> + + <!--Large--> + <style name="large_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">16sp</item> + </style> + + <style name="large_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">16sp</item> + </style> + + <style name="large_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">16sp</item> + </style> + + <style name="large_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">16sp</item> + </style> + + <!--Base--> + <style name="base_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">14sp</item> + </style> + + <style name="base_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">14sp</item> + </style> + + <style name="base_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">14sp</item> + </style> + + <style name="base_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">14sp</item> + </style> + + <!--Small--> + <style name="small_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="small_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="small_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="small_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">12sp</item> + </style> + + <!--X-Small--> + <style name="xsmall_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_bold</item> + <item name="android:textSize">11sp</item> + </style> + + <style name="xsmall_semi_bold"> + <item name="android:fontFamily">@font/ibm_plex_sans_semi_bold</item> + <item name="android:textSize">11sp</item> + </style> + + <style name="xsmall_medium"> + <item name="android:fontFamily">@font/ibm_plex_sans_medium</item> + <item name="android:textSize">11sp</item> + </style> + + <style name="xsmall_regular"> + <item name="android:fontFamily">@font/ibm_plex_sans_regular</item> + <item name="android:textSize">11sp</item> + </style> + +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/theme_attrs.xml b/app/src/main/res/values/theme_attrs.xml new file mode 100644 index 0000000..f24f314 --- /dev/null +++ b/app/src/main/res/values/theme_attrs.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <attr name="main_text_primary" format="reference|color" /> + <attr name="main_text_secondary" format="reference|color" /> + <attr name="main_text_tertiary" format="reference|color" /> + + <attr name="main_brand_primary" format="reference|color" /> + + <attr name="main_navigation_onNavigation" format="reference|color" /> + <attr name="main_navigation_bg" format="reference|color" /> + + <attr name="main_bg_surface" format="reference|color" /> + <attr name="main_bg_surface_alt" format="reference|color" /> + <attr name="main_bg_primary" format="reference|color" /> + <attr name="main_bg_secondary" format="reference|color" /> + <attr name="main_bg_tertiary" format="reference|color" /> + + <attr name="brand_text_secondary" format="reference|color" /> + <attr name="brand_text_primary" format="reference|color" /> + <attr name="brand_text_onMuted" format="reference|color" /> + <attr name="brand_text_onPrimary" format="reference|color" /> + + <attr name="brand_bg_primary" format="reference|color" /> + <attr name="brand_bg_muted" format="reference|color" /> + <attr name="brand_bg_muted_border" format="reference|color" /> + + <attr name="success_text_primary" format="reference|color" /> + <attr name="success_text_onMuted" format="reference|color" /> + <attr name="success_text_onPrimary" format="reference|color" /> + + <attr name="success_bg_primary" format="reference|color" /> + <attr name="success_bg_muted" format="reference|color" /> + <attr name="success_bg_muted_border" format="reference|color" /> + + <attr name="danger_text_primary" format="reference|color" /> + <attr name="danger_text_onMuted" format="reference|color" /> + <attr name="danger_text_onPrimary" format="reference|color" /> + + <attr name="danger_bg_primary" format="reference|color" /> + <attr name="danger_bg_muted" format="reference|color" /> + <attr name="danger_bg_muted_border" format="reference|color" /> + + <attr name="warning_text_onMuted" format="reference|color" /> + <attr name="warning_text_primary" format="reference|color" /> + <attr name="warning_text_onPrimary" format="reference|color" /> + + <attr name="warning_bg_muted" format="reference|color" /> + <attr name="warning_bg_primary" format="reference|color" /> + <attr name="warning_bg_muted_border" format="reference|color" /> + + <attr name="brand_alt_text_secondary" format="reference|color" /> + <attr name="brand_alt_text_primary" format="reference|color" /> + <attr name="brand_alt_text_onMuted" format="reference|color" /> + <attr name="brand_alt_text_onPrimary" format="reference|color" /> + + <attr name="brand_alt_bg_primary" format="reference|color" /> + <attr name="brand_alt_bg_muted" format="reference|color" /> + <attr name="brand_alt_bg_disabled" format="reference|color" /> + + <attr name="attention_text_onMuted" format="reference|color" /> + <attr name="attention_text_primary" format="reference|color" /> + <attr name="attention_text_onPrimary" format="reference|color" /> + + <attr name="attention_bg_muted" format="reference|color" /> + <attr name="attention_bg_muted_border" format="reference|color" /> + <attr name="attention_bg_primary" format="reference|color" /> + + <attr name="misc_home_bar" format="reference|color" /> + +</resources> diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..9ece324 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,178 @@ + +<resources xmlns:tools="http://schemas.android.com/tools"> + <!-- Base application theme. --> + + <style name="AppThemeBase" parent="Theme.MaterialComponents.Light.NoActionBar"> + </style> + + <style name="AppThemeBase.WhiteKnight"> + <!-- Primary brand color. --> + <item name="colorPrimary">@color/purple_500</item> + <item name="colorPrimaryVariant">@color/purple_700</item> + <item name="colorOnPrimary">@color/white</item> + <!-- Secondary brand color. --> + <item name="colorSecondary">@color/teal_200</item> + <item name="colorSecondaryVariant">@color/teal_700</item> + <item name="colorOnSecondary">@color/transparent</item> + + <item name="colorPrimaryDark">@android:color/transparent</item> + <!-- Status bar color. --> + <item name="android:statusBarColor" tools:targetApi="l">@color/colors_gray_100</item> + <!-- Customize your theme here. --> + + + <item name="main_text_primary">@color/colors_gray_100</item> + <item name="main_text_secondary">@color/colors_gray_50</item> + <item name="main_text_tertiary">@color/colors_gray_40</item> + + <item name="main_brand_primary">@color/colors_blue_60</item> + + <item name="main_navigation_onNavigation">@color/colors_white</item> + + <item name="main_navigation_bg">@color/colors_blue_60</item> <!-- ?attr/main_brand_primary--> + + <item name="main_bg_surface">@color/colors_gray_20</item> + <item name="main_bg_surface_alt">@color/colors_white</item> + <item name="main_bg_primary">@color/colors_white</item> + <item name="main_bg_secondary">@color/colors_gray_10</item> + <item name="main_bg_tertiary">@color/colors_gray_30</item> + + <item name="brand_text_secondary">@color/colors_blue_30</item> + <item name="brand_text_primary">@color/colors_blue_60</item> <!-- ?attr/main_brand_primary--> + <item name="brand_text_onMuted">@color/colors_blue_60</item> <!-- ?attr/main_brand_primary--> + <item name="brand_text_onPrimary">@color/colors_white</item> + + <item name="brand_bg_primary">@color/colors_blue_60</item> <!-- ?attr/main_brand_primary--> + <item name="brand_bg_muted">@color/colors_blue_10</item> + <item name="brand_bg_muted_border">@color/colors_blue_20</item> + + <item name="success_text_primary">@color/colors_green_60</item> + <item name="success_text_onMuted">@color/colors_green_60</item> + <item name="success_text_onPrimary">@color/colors_white</item> + + <item name="success_bg_primary">@color/colors_green_60</item> + <item name="success_bg_muted">@color/colors_green_10</item> + <item name="success_bg_muted_border">@color/colors_green_20</item> + + <item name="danger_text_primary">@color/colors_red_60</item> + <item name="danger_text_onMuted">@color/colors_red_60</item> + <item name="danger_text_onPrimary">@color/colors_white</item> + + <item name="danger_bg_primary">@color/colors_red_60</item> + <item name="danger_bg_muted">@color/colors_red_10</item> + <item name="danger_bg_muted_border">@color/colors_red_20</item> + + <item name="warning_text_onMuted">@color/colors_yellow_90</item> + <item name="warning_text_primary">@color/colors_yellow_70</item> + <item name="warning_text_onPrimary">@color/colors_yellow_100</item> + + <item name="warning_bg_muted">@color/colors_yellow_20</item> + <item name="warning_bg_primary">@color/colors_yellow_50</item> + <item name="warning_bg_muted_border">@color/colors_yellow_30</item> + + <item name="brand_alt_text_secondary">@color/colors_orange_30</item> + <item name="brand_alt_text_primary">@color/colors_orange_60</item> + <item name="brand_alt_text_onMuted">@color/colors_orange_60</item> + <item name="brand_alt_text_onPrimary">@color/colors_white</item> + + <item name="brand_alt_bg_primary">@color/colors_orange_60</item> + <item name="brand_alt_bg_muted">@color/colors_orange_10</item> + <item name="brand_alt_bg_disabled">@color/colors_orange_40</item> + + <item name="attention_text_onMuted">@color/colors_orange_60</item> + <item name="attention_text_primary">@color/colors_orange_60</item> + <item name="attention_text_onPrimary">@color/colors_white</item> + + <item name="attention_bg_muted">@color/colors_orange_10</item> + <item name="attention_bg_muted_border">@color/colors_orange_20</item> + <item name="attention_bg_primary">@color/colors_orange_60</item> + + <item name="misc_home_bar">@color/colors_black</item> + </style> + + <style name="AppThemeBase.DarkKnight"> + <!-- Primary brand color. --> + <item name="colorPrimary">@color/purple_200</item> + <item name="colorPrimaryVariant">@color/purple_700</item> + <item name="colorOnPrimary">@color/black</item> + <!-- Secondary brand color. --> + <item name="colorSecondary">@color/teal_200</item> + <item name="colorSecondaryVariant">@color/teal_200</item> + <item name="colorOnSecondary">@color/black</item> + + <item name="colorPrimaryDark">@android:color/transparent</item> + <!-- Status bar color. --> + <item name="android:statusBarColor" tools:targetApi="l">@color/colors_gray_100</item> + <!-- Customize your theme here. --> + + ------------------ New Dark theme Color ------------------------ + <item name="main_text_primary">@color/colors_gray_30</item> + <item name="main_text_secondary">@color/colors_gray_50</item> + <item name="main_text_tertiary">@color/colors_gray_60</item> + + <item name="main_brand_primary">@color/colors_blue_40</item> + + <item name="main_navigation_onNavigation">@color/colors_gray_30</item> <!-- //?attr/main_text_primary--> + <item name="main_navigation_bg">@color/colors_gray_80</item> + + <item name="main_bg_surface">@color/colors_gray_100</item> + <item name="main_bg_surface_alt">@color/colors_gray_100</item> + <item name="main_bg_primary">@color/colors_gray_80</item> + <item name="main_bg_secondary">@color/colors_gray_90</item> + <item name="main_bg_tertiary">@color/colors_gray_70</item> + + <item name="brand_text_secondary">@color/colors_blue_20</item> + + <item name="brand_text_primary">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_text_onMuted">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_text_onPrimary">@color/colors_white</item> + + <item name="brand_bg_primary">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_bg_muted">@color/colors_blue_90</item> + <item name="brand_bg_muted_border">@color/colors_blue_80</item> + + <item name="success_text_primary">@color/colors_green_40</item> + <item name="success_text_onMuted">@color/colors_green_30</item> + <item name="success_text_onPrimary">@color/colors_white</item> + + <item name="success_bg_primary">@color/colors_green_50</item> + <item name="success_bg_muted">@color/colors_green_80</item> + <item name="success_bg_muted_border">@color/colors_green_70</item> + + <item name="danger_text_primary">@color/colors_red_50</item> + <item name="danger_text_onMuted">@color/colors_red_30</item> + <item name="danger_text_onPrimary">@color/colors_white</item> + + <item name="danger_bg_primary">@color/colors_red_50</item> + <item name="danger_bg_muted">@color/colors_red_100</item> + <item name="danger_bg_muted_border">@color/colors_red_90</item> + + <item name="warning_text_onMuted">@color/colors_yellow_20</item> + <item name="warning_text_primary">@color/colors_yellow_50</item> + <item name="warning_text_onPrimary">@color/colors_yellow_100</item> + + <item name="warning_bg_muted">@color/colors_yellow_100</item> + <item name="warning_bg_primary">@color/colors_yellow_50</item> + <item name="warning_bg_muted_border">@color/colors_yellow_90</item> + + <item name="brand_alt_text_secondary">@color/colors_blue_20</item> + <item name="brand_alt_text_primary">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_alt_text_onMuted">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_alt_text_onPrimary">@color/colors_white</item> + + <item name="brand_alt_bg_primary">@color/colors_blue_40</item> <!-- ?attr/main_brand_primary--> + <item name="brand_alt_bg_muted">@color/colors_blue_90</item> + <item name="brand_alt_bg_disabled">@color/colors_blue_40</item> <!-- ?attr/brand_bg_primary--> + + <item name="attention_text_onMuted">@color/colors_orange_30</item> + <item name="attention_text_primary">@color/colors_orange_50</item> + <item name="attention_text_onPrimary">@color/colors_orange_100</item> + + <item name="attention_bg_muted">@color/colors_orange_100</item> + <item name="attention_bg_muted_border">@color/colors_orange_90</item> + <item name="attention_bg_primary">@color/colors_orange_50</item> + + <item name="misc_home_bar">@color/colors_white</item> + </style> + +</resources> \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Sample backup rules file; uncomment and customize as necessary. + See https://developer.android.com/guide/topics/data/autobackup + for details. + Note: This file is ignored for devices older that API 31 + See https://developer.android.com/about/versions/12/backup-restore +--> +<full-backup-content> + <!-- + <include domain="sharedpref" path="."/> + <exclude domain="sharedpref" path="device.xml"/> +--> +</full-backup-content> \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Sample data extraction rules file; uncomment and customize as necessary. + See https://developer.android.com/about/versions/12/backup-restore#xml-changes + for details. +--> +<data-extraction-rules> + <cloud-backup> + <!-- TODO: Use <include> and <exclude> to control what is backed up. + <include .../> + <exclude .../> + --> + </cloud-backup> + <!-- + <device-transfer> + <include .../> + <exclude .../> + </device-transfer> + --> +</data-extraction-rules> \ No newline at end of file diff --git a/app/src/test/java/com/example/bulletin/ExampleUnitTest.kt b/app/src/test/java/com/example/bulletin/ExampleUnitTest.kt new file mode 100644 index 0000000..c4f07b7 --- /dev/null +++ b/app/src/test/java/com/example/bulletin/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.bulletin + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..eaf7c0c --- /dev/null +++ b/build.gradle @@ -0,0 +1,10 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.2.2' apply false + id 'com.android.library' version '7.2.2' apply false + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..cd0519b --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..150f49e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Sep 20 16:28:33 IST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME