From 3d9524f4e1fc4d4e9a6c4c33c4c23bc0e54db47f Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Fri, 27 Oct 2017 14:37:15 +0300 Subject: [PATCH 001/140] autocomplete dict class --- .../droid/code/data/AutocompleteDictionary.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt diff --git a/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt b/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt new file mode 100644 index 0000000000..649a920c8d --- /dev/null +++ b/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt @@ -0,0 +1,46 @@ +package org.stepic.droid.code.data + +/** + * Class for fast search strings with common prefix + */ +class AutocompleteDictionary(private val dict: Array, needSort: Boolean = true) { + companion object { + /** + * Returns next in chars string + */ + fun incrementString(string: String): String { + val chars = string.toCharArray() + for (i in chars.size - 1 downTo 0) { + if (chars[i] + 1 < chars[i]) { + chars[i] = 0.toChar() + } else { + chars[i] = chars[i] + 1 + break + } + } + return if (chars[0] == 0.toChar()) { + 1.toChar() + String(chars) + } else { + String(chars) + } + } + + private fun getBinarySearchPosition(pos: Int) = + if (pos < 0) + -(pos + 1) + else + pos + } + + init { + if (needSort) { + dict.sort() + } + } + + fun getAutocompleteForPrefix(prefix: String): List { + val start = dict.binarySearch(prefix).let { getBinarySearchPosition(it) } + val end = dict.binarySearch(incrementString(prefix)).let { getBinarySearchPosition(it) } + return dict.slice(start until end) + } +} \ No newline at end of file From e9ad5fff5f3793f3c59983724d1c8284a6c46191 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Fri, 27 Oct 2017 16:46:16 +0300 Subject: [PATCH 002/140] autocomplete container --- .../droid/code/data/AutocompleteContainer.kt | 23 +++++++++++++++++++ .../droid/code/data/AutocompleteDictionary.kt | 2 +- .../org/stepic/droid/code/ui/CodeAnalyzer.kt | 19 +++++++++++++++ .../org/stepic/droid/code/ui/CodeEditor.kt | 1 + .../org/stepic/droid/util/StringExtensions.kt | 13 +++++++---- 5 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/code/data/AutocompleteContainer.kt diff --git a/app/src/main/java/org/stepic/droid/code/data/AutocompleteContainer.kt b/app/src/main/java/org/stepic/droid/code/data/AutocompleteContainer.kt new file mode 100644 index 0000000000..a24028dfbc --- /dev/null +++ b/app/src/main/java/org/stepic/droid/code/data/AutocompleteContainer.kt @@ -0,0 +1,23 @@ +package org.stepic.droid.code.data + +import org.stepic.droid.R +import org.stepic.droid.base.App + + +class AutocompleteContainer { + + private val autocomplete = hashMapOf( + "cpp" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_cpp)), + "cs" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_cs)), + "css" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_css)), + "html" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_html)), + "java" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_java)), + "js" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_js)), + "php" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_php)), + "py" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_py)), + "rb" to AutocompleteDictionary(App.getAppContext().resources.getStringArray(R.array.autocomplete_words_rb)) + ) + + fun getAutoCompleteForLangAndPrefix(lang: String, prefix: String): List = + autocomplete[lang]?.getAutocompleteForPrefix(prefix) ?: emptyList() +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt b/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt index 649a920c8d..681316fe8a 100644 --- a/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt +++ b/app/src/main/java/org/stepic/droid/code/data/AutocompleteDictionary.kt @@ -18,7 +18,7 @@ class AutocompleteDictionary(private val dict: Array, needSort: Boolean break } } - return if (chars[0] == 0.toChar()) { + return if (chars.isEmpty() || chars[0] == 0.toChar()) { 1.toChar() + String(chars) } else { String(chars) diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt index 3a497266e3..7041ba959f 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt @@ -1,7 +1,9 @@ package org.stepic.droid.code.ui +import org.stepic.droid.code.data.AutocompleteContainer import org.stepic.droid.util.countWhile import org.stepic.droid.util.substringOrNull +import org.stepic.droid.util.takeLastFromIndexWhile /** * Class for smart code analyzing @@ -28,6 +30,9 @@ object CodeAnalyzer { private val pairedSymbols = brackets + quotes + private val autocomplete = AutocompleteContainer() + private const val MIN_AUTOCOMPLETE = 1 + private fun getIndentForCurrentLine(cursorPosition: Int, text: String) : Int { val prevLineStart = text.substring(0, cursorPosition).lastIndexOf(LINE_BREAK) @@ -141,4 +146,18 @@ object CodeAnalyzer { } fun getBracketsPair(bracket: String) = brackets.entries.find { it.key == bracket || it.value == bracket } + + fun resolveAutocomplete(cursorPosition: Int, lang: String, text: String): List { + val next = getNextSymbol(cursorPosition, text) + if (next == null || Character.isWhitespace(next[0])) { + val prefix = text.takeLastFromIndexWhile(cursorPosition - 1) { // get token before cursor + !Character.isWhitespace(it) + } + + if (prefix != null && prefix.length > MIN_AUTOCOMPLETE) { + return autocomplete.getAutoCompleteForLangAndPrefix(lang, prefix) + } + } + return emptyList() + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt index 7863b02aba..a25ad18a03 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt @@ -239,6 +239,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 CodeAnalyzer.onTextReplaced(replacedStart, replacedCount, this, replacedText) CodeAnalyzer.onTextInserted(insertedStart, insertedCount, this) } + CodeAnalyzer.resolveAutocomplete(selectionStart, lang, text.toString()) highlightBrackets(selectionStart) highlightPublisher.onNext(editable) requestLayout() diff --git a/app/src/main/java/org/stepic/droid/util/StringExtensions.kt b/app/src/main/java/org/stepic/droid/util/StringExtensions.kt index 28f94bd575..5b783afb6c 100644 --- a/app/src/main/java/org/stepic/droid/util/StringExtensions.kt +++ b/app/src/main/java/org/stepic/droid/util/StringExtensions.kt @@ -4,15 +4,20 @@ package org.stepic.droid.util /* * Counts while predicate is true */ -inline fun String.countWhile(startIndex: Int = 0, predicate: (Char) -> Boolean) : Int { +inline fun String.countWhile(startIndex: Int = 0, reversed: Boolean = false, predicate: (Char) -> Boolean) : Int { + val delta = if (reversed) -1 else 1 var pos = startIndex - while (pos >= 0 && pos < this.length && predicate(this[pos])) pos++ - return pos - startIndex + while (pos >= 0 && pos < this.length && predicate(this[pos])) pos += delta + return delta * (pos - startIndex) } fun String.substringOrNull(start: Int, end: Int = length) = - if (0 <= start && end <= length) { + if (0 <= start && end <= length && start < end) { substring(start, end) } else { null } + + +inline fun String.takeLastFromIndexWhile(pos: Int, predicate: (Char) -> Boolean) = + this.substringOrNull(pos - this.countWhile(pos, reversed = true, predicate = predicate) + 1, pos) \ No newline at end of file From 108494d25cd9c5d4946b575ed379265cd8351fcd Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 1 Nov 2017 14:55:41 +0300 Subject: [PATCH 003/140] change style of code toolbar items --- .../java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt | 2 ++ app/src/main/res/layout/view_code_toolbar_item.xml | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt index 38b7e78a3c..616204fe39 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt @@ -1,6 +1,7 @@ package org.stepic.droid.ui.adapters import android.content.Context +import android.graphics.Typeface import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View @@ -46,6 +47,7 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter \ No newline at end of file From 8a5f63315fe1db28aca06e8aa735a7d81e7b93fb Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 1 Nov 2017 14:55:59 +0300 Subject: [PATCH 004/140] toolbar autocomplete expirements --- .../org/stepic/droid/code/ui/CodeAnalyzer.kt | 10 +++-- .../org/stepic/droid/code/ui/CodeEditor.kt | 14 ++++++- .../stepic/droid/code/ui/CodeEditorLayout.kt | 7 ++++ .../droid/ui/adapters/CodeToolbarAdapter.kt | 40 +++++++++++++++++-- .../droid/ui/fragments/CodeStepFragment.kt | 1 + .../org/stepic/droid/util/StringExtensions.kt | 2 +- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt index 7041ba959f..eede3c14d9 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt @@ -147,17 +147,19 @@ object CodeAnalyzer { fun getBracketsPair(bracket: String) = brackets.entries.find { it.key == bracket || it.value == bracket } - fun resolveAutocomplete(cursorPosition: Int, lang: String, text: String): List { + data class Autocomplete(val prefix: String?, val autocompleteWords: List) + + fun resolveAutocomplete(cursorPosition: Int, lang: String, text: String): Autocomplete { val next = getNextSymbol(cursorPosition, text) if (next == null || Character.isWhitespace(next[0])) { - val prefix = text.takeLastFromIndexWhile(cursorPosition - 1) { // get token before cursor + val prefix = text.takeLastFromIndexWhile(cursorPosition) { // get token before cursor !Character.isWhitespace(it) } if (prefix != null && prefix.length > MIN_AUTOCOMPLETE) { - return autocomplete.getAutoCompleteForLangAndPrefix(lang, prefix) + return Autocomplete(prefix, autocomplete.getAutoCompleteForLangAndPrefix(lang, prefix)) } } - return emptyList() + return Autocomplete(null, emptyList()) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt index f12dd4638d..938c6b6e1d 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt @@ -26,6 +26,7 @@ import org.stepic.droid.code.highlight.ParserContainer import org.stepic.droid.code.highlight.syntaxhighlight.ParseResult import org.stepic.droid.code.highlight.themes.CodeTheme import org.stepic.droid.code.highlight.themes.Presets +import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.util.removeGlobalLayoutListener import org.stepic.droid.util.* import java.util.concurrent.TimeUnit @@ -83,6 +84,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 var indentSize = DEFAULT_INDENT_SIZE internal set + var codeToolbarAdapter: CodeToolbarAdapter? = null internal var scrollContainer: CodeEditorLayout? = null set(value) { @@ -234,7 +236,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 CodeAnalyzer.onTextReplaced(replacedStart, replacedCount, this, replacedText) CodeAnalyzer.onTextInserted(insertedStart, insertedCount, this) } - CodeAnalyzer.resolveAutocomplete(selectionStart, lang, text.toString()) + resolveAutocomplete() highlightBrackets(selectionStart) highlightPublisher.onNext(editable) requestLayout() @@ -255,6 +257,16 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 override fun onSelectionChanged(start: Int, end: Int) { super.onSelectionChanged(start, end) highlightBrackets(start) + resolveAutocomplete() + } + + private fun resolveAutocomplete() { + if (lang == null) return + val (prefix, words) = CodeAnalyzer.resolveAutocomplete(selectionStart, lang, text.toString()) + codeToolbarAdapter?.apply { + autoCompleteWords = words + autoCompletePrefix = prefix + } } private fun highlightBrackets(cursorPosition: Int) { diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt index d15469e3fa..2224d525a4 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt @@ -8,6 +8,7 @@ import android.view.LayoutInflater import org.stepic.droid.R import org.stepic.droid.code.highlight.themes.CodeTheme import org.stepic.droid.code.highlight.themes.Presets +import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.util.insertText class CodeEditorLayout @@ -35,6 +36,12 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 val indentSize: Int get() = codeEditor.indentSize + var codeToolbarAdapter: CodeToolbarAdapter? + get() = codeEditor.codeToolbarAdapter + set(value) { + codeEditor.codeToolbarAdapter = value + } + init { LayoutInflater.from(context).inflate(R.layout.view_code_editor, this, true) codeEditor = findViewById(R.id.codeEdit) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt index 616204fe39..d921ebe7a9 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt @@ -3,11 +3,16 @@ package org.stepic.droid.ui.adapters import android.content.Context import android.graphics.Typeface import android.support.v7.widget.RecyclerView +import android.text.Spannable +import android.text.SpannableString +import android.text.style.BackgroundColorSpan +import android.text.style.ForegroundColorSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import org.stepic.droid.R +import org.stepic.droid.code.highlight.themes.Presets import org.stepic.droid.model.code.symbolsForLanguage import org.stepic.droid.ui.listeners.OnItemClickListener @@ -17,10 +22,28 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter = emptyList() + set(value) { + field = value + notifyDataSetChanged() + } + var autoCompletePrefix: String? = null + var onSymbolClickListener: OnSymbolClickListener? = null private var symbols: Array = emptyArray() private val onItemClickListener = OnItemClickListener { position -> - val symbol = symbols[position] + val autocompleteSize = autoCompleteWords.size + val symbol = if (position < autocompleteSize) { + val word = autoCompleteWords[position] + val pref = autoCompletePrefix + if (pref != null) { + word.removePrefix(pref) + " " + } else { + "" + } + } else { + symbols[position - autocompleteSize] + } onSymbolClickListener?.onSymbolClick(symbol) } @@ -35,10 +58,19 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter(R.id.codeToolbarSymbol) @@ -50,7 +82,7 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter Boolean) = - this.substringOrNull(pos - this.countWhile(pos, reversed = true, predicate = predicate) + 1, pos) \ No newline at end of file + this.substringOrNull(pos - this.countWhile(pos - 1, reversed = true, predicate = predicate), pos) \ No newline at end of file From 89d0c55e20438edd3ca83770758bc95fd5acb600 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 1 Nov 2017 16:07:11 +0300 Subject: [PATCH 005/140] prefix background color --- .../org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt | 7 +++++-- app/src/main/res/values/colors.xml | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt index d921ebe7a9..f7dee8a46a 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt @@ -2,17 +2,16 @@ package org.stepic.droid.ui.adapters import android.content.Context import android.graphics.Typeface +import android.support.v4.content.ContextCompat import android.support.v7.widget.RecyclerView import android.text.Spannable import android.text.SpannableString import android.text.style.BackgroundColorSpan -import android.text.style.ForegroundColorSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import org.stepic.droid.R -import org.stepic.droid.code.highlight.themes.Presets import org.stepic.droid.model.code.symbolsForLanguage import org.stepic.droid.ui.listeners.OnItemClickListener @@ -22,6 +21,10 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter = emptyList() set(value) { field = value diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index eb4d8eb9e8..2446bf5f7a 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -121,6 +121,7 @@ #DBDBDB #EEEEEE + #CCCCCC #AAFF0000 #AAFFD77A @color/new_accent_color From 8b4d468c325ccb81ea1db4fedbaa0d277275e663 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 1 Nov 2017 17:29:31 +0300 Subject: [PATCH 006/140] toolbar separator --- .../droid/ui/adapters/CodeToolbarAdapter.kt | 69 ++++++++++++------- .../ui/fragments/CodePlaygroundFragment.kt | 1 + .../layout/view_code_toolbar_separator.xml | 5 ++ 3 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 app/src/main/res/layout/view_code_toolbar_separator.xml diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt index f7dee8a46a..3e9e8bbe73 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt @@ -15,7 +15,11 @@ import org.stepic.droid.R import org.stepic.droid.model.code.symbolsForLanguage import org.stepic.droid.ui.listeners.OnItemClickListener -class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter() { +class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter() { + companion object { + private const val SEPARATOR_VIEW_TYPE = 1 + private const val ELEMENT_VIEW_TYPE = 0 + } interface OnSymbolClickListener { fun onSymbolClick(symbol: String) @@ -32,20 +36,18 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter = emptyArray() private val onItemClickListener = OnItemClickListener { position -> - val autocompleteSize = autoCompleteWords.size - val symbol = if (position < autocompleteSize) { - val word = autoCompleteWords[position] - val pref = autoCompletePrefix - if (pref != null) { - word.removePrefix(pref) + " " - } else { - "" - } + val symbol = if (position < autocompleteItemsCount - 1) { + autoCompletePrefix?.let { + autoCompleteWords[position].removePrefix(it) + " " + } ?: "" } else { - symbols[position - autocompleteSize] + symbols[position - autocompleteItemsCount] } onSymbolClickListener?.onSymbolClick(symbol) } @@ -55,25 +57,43 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter + CodeToolbarSeparator(inflater.inflate(R.layout.view_code_toolbar_separator, parent, false)) + + ELEMENT_VIEW_TYPE -> + CodeToolbarItem(inflater.inflate(R.layout.view_code_toolbar_item, parent, false), onItemClickListener) + + else -> throw IllegalArgumentException("Wrong view type: $viewType") + } } - override fun onBindViewHolder(holder: CodeToolbarItem, position: Int) { - val autocompleteSize = autoCompleteWords.size - if (position < autocompleteSize) { - val word = SpannableString(autoCompleteWords[position]) - autoCompletePrefix?.let { - word.setSpan(BackgroundColorSpan(Presets.themes[0].bracketsHighlight), 0, it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (getItemViewType(position)) { + ELEMENT_VIEW_TYPE -> (holder as CodeToolbarItem).let { + if (autoCompleteWords.isNotEmpty() && position < autocompleteItemsCount) { + val word = SpannableString(autoCompleteWords[position]) + autoCompletePrefix?.let { + word.setSpan(autocompletePrefixBackgroundSpan, 0, it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + it.bindData(word) + } else { + it.bindData(SpannableString(symbols[position - autocompleteItemsCount])) + } } - holder.bindData(word) - } else { - holder.bindData(SpannableString(symbols[position - autocompleteSize])) } } - override fun getItemCount(): Int = symbols.size + autoCompleteWords.size + override fun getItemCount(): Int = symbols.size + autocompleteItemsCount class CodeToolbarItem(itemView: View, onItemClickListener: OnItemClickListener) : RecyclerView.ViewHolder(itemView) { private val codeToolbarSymbol = itemView.findViewById(R.id.codeToolbarSymbol) @@ -89,5 +109,6 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter + \ No newline at end of file From b2bf675be529055461761dbdc618a9e7a3db8c6e Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 1 Nov 2017 18:36:01 +0300 Subject: [PATCH 007/140] naming & clean up --- .../java/org/stepic/droid/code/ui/CodeAnalyzer.kt | 13 +++++++------ .../java/org/stepic/droid/code/ui/CodeEditor.kt | 2 +- .../stepic/droid/ui/adapters/CodeToolbarAdapter.kt | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt index eede3c14d9..a4cff3f53b 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeAnalyzer.kt @@ -31,7 +31,7 @@ object CodeAnalyzer { private val pairedSymbols = brackets + quotes private val autocomplete = AutocompleteContainer() - private const val MIN_AUTOCOMPLETE = 1 + private const val MIN_AUTOCOMPLETE_LENGTH = 2 private fun getIndentForCurrentLine(cursorPosition: Int, text: String) : Int { @@ -147,19 +147,20 @@ object CodeAnalyzer { fun getBracketsPair(bracket: String) = brackets.entries.find { it.key == bracket || it.value == bracket } - data class Autocomplete(val prefix: String?, val autocompleteWords: List) - fun resolveAutocomplete(cursorPosition: Int, lang: String, text: String): Autocomplete { + fun resolveAutocomplete(cursorPosition: Int, lang: String, text: String): AutocompleteState { val next = getNextSymbol(cursorPosition, text) if (next == null || Character.isWhitespace(next[0])) { val prefix = text.takeLastFromIndexWhile(cursorPosition) { // get token before cursor !Character.isWhitespace(it) } - if (prefix != null && prefix.length > MIN_AUTOCOMPLETE) { - return Autocomplete(prefix, autocomplete.getAutoCompleteForLangAndPrefix(lang, prefix)) + if (prefix != null && prefix.length >= MIN_AUTOCOMPLETE_LENGTH) { + return AutocompleteState(prefix, autocomplete.getAutoCompleteForLangAndPrefix(lang, prefix)) } } - return Autocomplete(null, emptyList()) + return AutocompleteState(null, emptyList()) } + + data class AutocompleteState(val prefix: String?, val autocompleteWords: List) } \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt index 938c6b6e1d..1b9fb7420b 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeEditor.kt @@ -262,8 +262,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 private fun resolveAutocomplete() { if (lang == null) return - val (prefix, words) = CodeAnalyzer.resolveAutocomplete(selectionStart, lang, text.toString()) codeToolbarAdapter?.apply { + val (prefix, words) = CodeAnalyzer.resolveAutocomplete(selectionStart, lang, text.toString()) autoCompleteWords = words autoCompletePrefix = prefix } diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt index 3e9e8bbe73..b8c03bf018 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CodeToolbarAdapter.kt @@ -37,7 +37,7 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter = emptyArray() @@ -80,7 +80,7 @@ class CodeToolbarAdapter(private val context: Context) : RecyclerView.Adapter (holder as CodeToolbarItem).let { - if (autoCompleteWords.isNotEmpty() && position < autocompleteItemsCount) { + if (position < autocompleteItemsCount) { val word = SpannableString(autoCompleteWords[position]) autoCompletePrefix?.let { word.setSpan(autocompletePrefixBackgroundSpan, 0, it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) From e1a45a10cf3eeeb539328152f99f870686e1c6e0 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Thu, 2 Nov 2017 15:52:34 +0300 Subject: [PATCH 008/140] add max-width bound to images in steps --- app/src/main/assets/wysiwyg.css | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/wysiwyg.css b/app/src/main/assets/wysiwyg.css index 3cc4b3d138..7852ad885a 100644 --- a/app/src/main/assets/wysiwyg.css +++ b/app/src/main/assets/wysiwyg.css @@ -133,6 +133,7 @@ img { display: block; + max-width: 100%; &.wysiwyg-float-left, &.wysiwyg-float-right { display: inline-block; From a70d1a572e998e144a8148240257d5b8b7914c70 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Thu, 2 Nov 2017 17:19:01 +0300 Subject: [PATCH 009/140] FindCoursesFragment.java -> FindCoursesFragment.kt --- .../droid/ui/activities/MainFeedActivity.kt | 2 +- .../ui/fragments/FindCoursesFragment.java | 125 ------------------ .../droid/ui/fragments/FindCoursesFragment.kt | 102 ++++++++++++++ .../fragments/PopularCoursesAloneFragment.kt | 2 +- .../java/org/stepic/droid/util/MonadUtil.kt | 5 + 5 files changed, 109 insertions(+), 127 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java create mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt create mode 100644 app/src/main/java/org/stepic/droid/util/MonadUtil.kt diff --git a/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt b/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt index 4955295f8f..271b401418 100644 --- a/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt +++ b/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt @@ -256,7 +256,7 @@ class MainFeedActivity : BackToExitActivityWithSmartLockBase(), getNextFragmentOrNull(currentFragmentTag, HomeFragment::class.java.simpleName, HomeFragment.Companion::newInstance) } R.id.find_courses -> { - getNextFragmentOrNull(currentFragmentTag, FindCoursesFragment::class.java.simpleName, FindCoursesFragment::newInstance) + getNextFragmentOrNull(currentFragmentTag, FindCoursesFragment::class.java.simpleName, FindCoursesFragment.Companion::newInstance) } R.id.profile -> { getNextFragmentOrNull(currentFragmentTag, ProfileFragment::class.java.simpleName, ProfileFragment.Companion::newInstance) diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java deleted file mode 100644 index cec2cc9e11..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.stepic.droid.ui.fragments; - -import android.app.SearchManager; -import android.app.SearchableInfo; -import android.content.ComponentName; -import android.content.Context; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.SearchView; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; - -import org.stepic.droid.R; -import org.stepic.droid.base.CoursesDatabaseFragmentBase; -import org.stepic.droid.storage.operations.Table; -import org.stepic.droid.ui.listeners.OnRootTouchedListener; -import org.stepic.droid.ui.util.ToolbarHelperKt; - -public class FindCoursesFragment extends CoursesDatabaseFragmentBase { - - public static FindCoursesFragment newInstance() { - return new FindCoursesFragment(); - } - - private SearchView searchView = null; - private MenuItem menuItem = null; - private boolean handledByRoot = false; - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - setHasOptionsMenu(true); - super.onViewCreated(view, savedInstanceState); - ToolbarHelperKt.initCenteredToolbar(this, getTitle(), false); - rootView.setParentTouchEvent(new OnRootTouchedListener() { - @Override - public void makeBeforeChildren() { - collapseAndHide(true); - } - }); - - listOfCoursesView.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - if (!handledByRoot) { - collapseAndHide(false); - } - handledByRoot = false; - } - } - }); - - } - - @Override - public void onDestroyView() { - if (listOfCoursesView != null) { - listOfCoursesView.setOnFocusChangeListener(null); - } - super.onDestroyView(); - } - - private void collapseAndHide(boolean rootHandle) { - if (searchView != null && menuItem != null && menuItem.isActionViewExpanded()) { - if (rootHandle) handledByRoot = true; - hideSoftKeypad();//in collapse action view keypad going to invisible after animation - menuItem.collapseActionView(); - } - } - - @Override - protected Table getCourseType() { - return Table.featured; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.search_menu, menu); - super.onCreateOptionsMenu(menu, inflater); - - SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); - menuItem = menu.findItem(R.id.action_search); - searchView = (SearchView) menuItem.getActionView(); - - ImageView closeImageView = searchView.findViewById(R.id.search_close_btn); - closeImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), getCloseIconDrawableRes())); - - ComponentName componentName = getActivity().getComponentName(); - SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName); - searchView.setSearchableInfo(searchableInfo); - searchView.setMaxWidth(20000);//it is dirty workaround for expand in landscape - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - collapseAndHide(false); - return false; - } - - @Override - public boolean onQueryTextChange(String newText) { - return false; - } - }); - } - - @Override - public void onDestroyOptionsMenu() { - super.onDestroyOptionsMenu(); - - if (searchView != null) { - searchView.setOnQueryTextListener(null); - } - searchView = null; - } - - @StringRes - protected int getTitle () { - return R.string.catalog_title; - } -} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt new file mode 100644 index 0000000000..b00be539a0 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt @@ -0,0 +1,102 @@ +package org.stepic.droid.ui.fragments + +import android.app.SearchManager +import android.content.Context +import android.os.Bundle +import android.support.annotation.StringRes +import android.support.v4.content.ContextCompat +import android.support.v7.widget.SearchView +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.widget.ImageView +import org.stepic.droid.R +import org.stepic.droid.base.CoursesDatabaseFragmentBase +import org.stepic.droid.storage.operations.Table +import org.stepic.droid.ui.util.initCenteredToolbar +import org.stepic.droid.util.liftM2 + +open class FindCoursesFragment: CoursesDatabaseFragmentBase() { + companion object { + fun newInstance() = FindCoursesFragment() + } + + private var searchView: SearchView? = null + private var menuItem: MenuItem? = null + private var handledByRoot = false + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + setHasOptionsMenu(true) + super.onViewCreated(view, savedInstanceState) + initCenteredToolbar(getTitle(), false) + rootView.setParentTouchEvent { collapseAndHide(true) } + + listOfCoursesView.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + if (!handledByRoot) { + collapseAndHide(false) + } + handledByRoot = false + } + } + + } + + override fun onDestroyView() { + listOfCoursesView.onFocusChangeListener = null + super.onDestroyView() + } + + private fun collapseAndHide(rootHandle: Boolean) { + searchView.liftM2(menuItem) { _, menuItem -> + if (menuItem.isActionViewExpanded) { + if (rootHandle) handledByRoot = true + hideSoftKeypad() + menuItem.collapseActionView() + } + } + } + + override fun getCourseType() = Table.featured + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.search_menu, menu) + super.onCreateOptionsMenu(menu, inflater) + + val searchManager = activity.getSystemService(Context.SEARCH_SERVICE) as SearchManager + menuItem = menu.findItem(R.id.action_search) + + searchView = menuItem?.actionView as SearchView + searchView?.let { + val closeImageView: ImageView = it.findViewById(R.id.search_close_btn) + closeImageView.setImageDrawable(ContextCompat.getDrawable(context, getCloseIconDrawableRes())) + + val componentName = activity.componentName + val searchableInfo = searchManager.getSearchableInfo(componentName) + it.setSearchableInfo(searchableInfo) + it.maxWidth = 20000 + it.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + collapseAndHide(false) + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + return false + } + }) + } + + } + + override fun onDestroyOptionsMenu() { + super.onDestroyOptionsMenu() + searchView?.setOnQueryTextListener(null) + searchView = null + } + + + @StringRes + protected open fun getTitle() = R.string.catalog_title +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt index ce2fc19a8c..672ef8f615 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt @@ -9,7 +9,7 @@ class PopularCoursesAloneFragment : FindCoursesFragment() { fun newInstance(): PopularCoursesAloneFragment = PopularCoursesAloneFragment() } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { //no-op } diff --git a/app/src/main/java/org/stepic/droid/util/MonadUtil.kt b/app/src/main/java/org/stepic/droid/util/MonadUtil.kt new file mode 100644 index 0000000000..16a67d1a34 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/util/MonadUtil.kt @@ -0,0 +1,5 @@ +package org.stepic.droid.util + + +inline fun L?.liftM2(r: R?, block: (L, R) -> Z) = + this?.let { l -> r?.let { r -> block(l, r) } } \ No newline at end of file From cf460e53d7e320583784f067b9b2355774e426cd Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Thu, 2 Nov 2017 20:31:40 +0300 Subject: [PATCH 010/140] make first version of circle progress view (bad quality) --- .../view_hoders/CourseItemViewHolder.kt | 7 ++ .../droid/ui/custom/CircleProgressView.kt | 92 +++++++++++++++++++ .../res/drawable/login_edit_text_stroke.xml | 4 +- app/src/main/res/drawable/popup_arrow_up.xml | 2 +- .../main/res/drawable/video_seekbar_thumb.xml | 2 +- app/src/main/res/layout/new_course_item.xml | 23 +++++ .../main/res/layout/view_course_progress.xml | 8 ++ app/src/main/res/values/attrs.xml | 6 ++ app/src/main/res/values/dimens.xml | 2 + 9 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt create mode 100644 app/src/main/res/layout/view_course_progress.xml diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt index ceb3f43e57..aff428a6c4 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt @@ -74,6 +74,8 @@ class CourseItemViewHolder( private val courseItemMore = view.courseItemMore private val learnersCountContainer = view.learnersCountContainer private val courseWidgetInfo = view.courseWidgetInfo + private val courseItemProgress = view.courseItemProgressView + private val courseItemProgressTitle = view.courseItemProgressTitle init { @@ -207,6 +209,11 @@ class CourseItemViewHolder( showJoinButton() } + val progressPart = (position % 10).toFloat() / 10f + courseItemProgress.progress = progressPart + courseItemProgressTitle.text = "%.2f%%".format(progressPart * 100) + + courseItemMore.visibility = if (showMore) { View.VISIBLE } else { diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt new file mode 100644 index 0000000000..75cbaf70fb --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt @@ -0,0 +1,92 @@ +package org.stepic.droid.ui.custom + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.support.annotation.ColorInt +import android.util.AttributeSet +import android.view.View +import org.stepic.droid.R +import org.stepic.droid.util.ColorUtil +import org.stepic.droid.util.DpPixelsHelper + +class CircleProgressView +@JvmOverloads +constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0) + : View(context, attributeSet, defStyleAttr, defStyleRes) { + + companion object { + private const val MAX_DEGREES = 360f + } + + var progress: Float = 0.0f + + //Rectangles + private val oval = RectF() + + //Paints + private val backgroundPaint = Paint() + private val foregroundPaint = Paint() + + + //Colors (with defaults) + @ColorInt + private var backgroundPaintColor = ColorUtil.getColorArgb(R.color.new_accent_color, context) + @ColorInt + private var foregroundPaintColor = ColorUtil.getColorArgb(R.color.stepic_brand_primary, context) + + private var strokeWidth = DpPixelsHelper.convertDpToPixel(2f) + + init { + parseAttributes(context.obtainStyledAttributes(attributeSet, R.styleable.CircleProgressView)) + + setupPaint(backgroundPaint, backgroundPaintColor) + setupPaint(foregroundPaint, foregroundPaintColor) + + } + + /** + * Parse the attributes passed to the view from the XML + * + * @param a the attributes to parse + */ + private fun parseAttributes(a: TypedArray) { + try { + backgroundPaintColor = a.getColor(R.styleable.CircleProgressView_progressBackgroundColor, backgroundPaintColor) + foregroundPaintColor = a.getColor(R.styleable.CircleProgressView_progressForegroundColor, foregroundPaintColor) + strokeWidth = a.getDimension(R.styleable.CircleProgressView_progressBarStroke, strokeWidth) + } finally { + a.recycle() + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + + setupBounds(w, h) + } + + private fun setupBounds(layoutWidth: Int, layoutHeight: Int) { + oval.set(paddingLeft + strokeWidth, + paddingTop + strokeWidth, + layoutWidth - paddingRight - strokeWidth, + layoutHeight - paddingBottom - strokeWidth) + } + + private fun setupPaint(paint: Paint, paintColor: Int) { + paint.color = paintColor + paint.isAntiAlias = true + paint.style = Paint.Style.STROKE + paint.strokeWidth = strokeWidth + } + + + override fun onDraw(canvas: Canvas) { + canvas.drawArc(oval, MAX_DEGREES, MAX_DEGREES, false, backgroundPaint) + val progressDegrees = progress * MAX_DEGREES + canvas.drawArc(oval, -90F, progressDegrees, false, foregroundPaint) + } + +} diff --git a/app/src/main/res/drawable/login_edit_text_stroke.xml b/app/src/main/res/drawable/login_edit_text_stroke.xml index 0872de94fb..873ce48e42 100644 --- a/app/src/main/res/drawable/login_edit_text_stroke.xml +++ b/app/src/main/res/drawable/login_edit_text_stroke.xml @@ -4,14 +4,14 @@ - + - + \ No newline at end of file diff --git a/app/src/main/res/drawable/popup_arrow_up.xml b/app/src/main/res/drawable/popup_arrow_up.xml index 95877ceb41..4da6974a95 100644 --- a/app/src/main/res/drawable/popup_arrow_up.xml +++ b/app/src/main/res/drawable/popup_arrow_up.xml @@ -7,7 +7,7 @@ android:pivotX="-40%" android:pivotY="87%" > - + diff --git a/app/src/main/res/drawable/video_seekbar_thumb.xml b/app/src/main/res/drawable/video_seekbar_thumb.xml index 5bc9ff922b..2cb3bb91f9 100644 --- a/app/src/main/res/drawable/video_seekbar_thumb.xml +++ b/app/src/main/res/drawable/video_seekbar_thumb.xml @@ -2,7 +2,7 @@ - + diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index cf2d1ae99c..af931ba0b0 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -93,6 +93,29 @@ android:textSize="16sp" tools:ignore="MissingPrefix" tools:text="999K"/> + + + + diff --git a/app/src/main/res/layout/view_course_progress.xml b/app/src/main/res/layout/view_course_progress.xml new file mode 100644 index 0000000000..6e9e4da33f --- /dev/null +++ b/app/src/main/res/layout/view_course_progress.xml @@ -0,0 +1,8 @@ + + + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 64c506094a..e1ac79bf8a 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -11,6 +11,12 @@ + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 873d2378cc..4cba6fe7a6 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -116,6 +116,8 @@ 20sp 24dp 0dp + 11dp + 2dp From bd90fb694df20d565138f300fd03b3ba78eaa4e7 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Thu, 2 Nov 2017 20:50:08 +0300 Subject: [PATCH 011/140] due to progresses are to small background was seen behind foreground (anti-aliasing is already enabled). So, don't draw background behind. Sometimes background and foreground can have spaces between. But it is ok for small circles. save old strategy for large circles --- .../droid/ui/custom/CircleProgressView.kt | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt index 75cbaf70fb..d4d036e227 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt @@ -12,6 +12,10 @@ import org.stepic.droid.R import org.stepic.droid.util.ColorUtil import org.stepic.droid.util.DpPixelsHelper + +/** + * this view has different implementation of onDraw, based on stroke of circle + */ class CircleProgressView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0) @@ -19,10 +23,13 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: companion object { private const val MAX_DEGREES = 360f + private const val DEFAULT_STROKE_WIDTH_DP = 2f } var progress: Float = 0.0f + private val strokeBound = DpPixelsHelper.convertDpToPixel(5f) //if < 5dp -> onDraw with space, >= 5dp -> without spaces + //Rectangles private val oval = RectF() @@ -30,14 +37,18 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: private val backgroundPaint = Paint() private val foregroundPaint = Paint() - //Colors (with defaults) @ColorInt private var backgroundPaintColor = ColorUtil.getColorArgb(R.color.new_accent_color, context) @ColorInt private var foregroundPaintColor = ColorUtil.getColorArgb(R.color.stepic_brand_primary, context) - private var strokeWidth = DpPixelsHelper.convertDpToPixel(2f) + private var isStrokeSmall: Boolean = true + private var strokeWidth = DpPixelsHelper.convertDpToPixel(DEFAULT_STROKE_WIDTH_DP) + set(value) { + isStrokeSmall = DpPixelsHelper.convertPixelsToDp(value, context) < strokeBound + field = value + } init { parseAttributes(context.obtainStyledAttributes(attributeSet, R.styleable.CircleProgressView)) @@ -82,8 +93,22 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: paint.strokeWidth = strokeWidth } - override fun onDraw(canvas: Canvas) { + when (isStrokeSmall) { + true -> drawSmallStroke(canvas) + false -> drawLargeStroke(canvas) + } + } + + private fun drawSmallStroke(canvas: Canvas) { + val progressDegrees: Int = (progress * MAX_DEGREES).toInt() + val remain = MAX_DEGREES - progressDegrees + + canvas.drawArc(oval, progressDegrees - 90F, remain, false, backgroundPaint) + canvas.drawArc(oval, -90F, progressDegrees.toFloat(), false, foregroundPaint) + } + + private fun drawLargeStroke(canvas: Canvas) { canvas.drawArc(oval, MAX_DEGREES, MAX_DEGREES, false, backgroundPaint) val progressDegrees = progress * MAX_DEGREES canvas.drawArc(oval, -90F, progressDegrees, false, foregroundPaint) From 04b4b57f0e84b1b55f429f274a3c4f33c3dfd612 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Thu, 2 Nov 2017 21:23:33 +0300 Subject: [PATCH 012/140] set default stroke width for progress in dimens --- app/src/main/res/layout/new_course_item.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index af931ba0b0..4376d31ef4 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -99,6 +99,7 @@ android:layout_width="@dimen/course_item_progress_size" android:layout_height="@dimen/course_item_progress_size" android:layout_centerVertical="true" + app:progressBarStroke="@dimen/course_item_progress_bar_size" android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:layout_toEndOf="@id/learnersCountText" From 6b4c8df404c622ffa05e032bc558579532fa1e15 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Fri, 3 Nov 2017 12:28:34 +0300 Subject: [PATCH 013/140] api point for search queries --- app/src/main/java/org/stepic/droid/model/SearchQuery.kt | 3 +++ app/src/main/java/org/stepic/droid/web/Api.java | 2 ++ app/src/main/java/org/stepic/droid/web/ApiImpl.java | 5 +++++ app/src/main/java/org/stepic/droid/web/QueriesResponse.kt | 5 +++++ .../java/org/stepic/droid/web/StepicRestLoggedService.java | 3 +++ 5 files changed, 18 insertions(+) create mode 100644 app/src/main/java/org/stepic/droid/model/SearchQuery.kt create mode 100644 app/src/main/java/org/stepic/droid/web/QueriesResponse.kt diff --git a/app/src/main/java/org/stepic/droid/model/SearchQuery.kt b/app/src/main/java/org/stepic/droid/model/SearchQuery.kt new file mode 100644 index 0000000000..6847ee366a --- /dev/null +++ b/app/src/main/java/org/stepic/droid/model/SearchQuery.kt @@ -0,0 +1,3 @@ +package org.stepic.droid.model + +data class SearchQuery(val text: String) \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index f458003728..482ec420ad 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -67,6 +67,8 @@ enum TokenType { Call getSearchResultsCourses(int page, String rawQuery); + Single getSearchQueries(String query); + Call getCourses(int page, long[] ids); Call createNewAttempt(long stepId); diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 6a5da014c3..d189215f3f 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -505,6 +505,11 @@ public Call getSearchResultsCourses(int page, String rawQu return loggedService.getSearchResults(page, encodedQuery, type); } + @Override + public Single getSearchQueries(String query) { + return loggedService.getSearchQueries(query); + } + @Override public Call getCourses(int page, @Nullable long[] ids) { if (ids == null || ids.length == 0) { diff --git a/app/src/main/java/org/stepic/droid/web/QueriesResponse.kt b/app/src/main/java/org/stepic/droid/web/QueriesResponse.kt new file mode 100644 index 0000000000..02467e6cc1 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/QueriesResponse.kt @@ -0,0 +1,5 @@ +package org.stepic.droid.web + +import org.stepic.droid.model.SearchQuery + +data class QueriesResponse(val queries: List) \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index 220e4dcdab..9b650701b0 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -66,6 +66,9 @@ public interface StepicRestLoggedService { Call getSearchResults(@Query("page") int page, @Query(value = "query", encoded = true) String encodedQuery, @Query("type") String type); + @GET("api/queries") + Single getSearchQueries(@Query("query") String query); + @GET("api/courses") Call getCourses(@Query("page") int page, @Query("ids[]") long[] courseIds); From 3aebc28c94bdf3ec70b892ab8d88b2a4a1db1288 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 14:45:50 +0300 Subject: [PATCH 014/140] add progress object to course (optional) --- .../PersistentCourseListPresenter.kt | 56 +++++++++++++------ .../java/org/stepic/droid/model/Course.java | 12 ++++ .../java/org/stepic/droid/model/Progress.kt | 32 ++++++++++- .../org/stepic/droid/model/ProgressTest.kt | 16 ++++++ 4 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 app/src/test/java/org/stepic/droid/model/ProgressTest.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt index 2a4cd7ad5b..7df2e213e4 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt @@ -166,8 +166,13 @@ class PersistentCourseListPresenter if ((filteredCourseList.size < MIN_COURSES_ON_SCREEN) && hasNextPage.get()) { //try to load next in loop } else { + val progressesMap = getProgressesFromDb(filteredCourseList) val coursesForShow = when (courseType) { - Table.enrolled -> sortByLastAction(filteredCourseList) + Table.enrolled -> { + //progresses should be shown only for enrolled lists + applyProgressesToCourses(progressesMap, filteredCourseList) + sortByLastAction(filteredCourseList, progressesMap) + } else -> filteredCourseList } mainHandler.post { @@ -193,15 +198,19 @@ class PersistentCourseListPresenter private fun getFromDatabaseAndShow(applyFilter: Boolean, courseType: Table) { val coursesBeforeLoading = databaseFacade.getAllCourses(courseType).filterNotNull() if (coursesBeforeLoading.isNotEmpty()) { - val coursesForShow = if (courseType == Table.enrolled) { - sortByLastAction(coursesBeforeLoading) - } else { - if (!applyFilter && !sharedPreferenceHelper.filterForFeatured.contains(StepikFilter.PERSISTENT)) { - filterApplicator.getFilteredFeaturedFromDefault(coursesBeforeLoading) - } else { - filterApplicator.getFilteredFeaturedFromSharedPrefs(coursesBeforeLoading) - } - } + val progressMap = getProgressesFromDb(coursesBeforeLoading) + val coursesForShow = + if (courseType == Table.enrolled) { + //apply only for enrolled list/carousel + applyProgressesToCourses(progressMap, coursesBeforeLoading) + sortByLastAction(coursesBeforeLoading, progressMap) + } else { + if (!applyFilter && !sharedPreferenceHelper.filterForFeatured.contains(StepikFilter.PERSISTENT)) { + filterApplicator.getFilteredFeaturedFromDefault(coursesBeforeLoading) + } else { + filterApplicator.getFilteredFeaturedFromSharedPrefs(coursesBeforeLoading) + } + } if (coursesForShow.isNotEmpty()) { mainHandler.post { view?.showCourses(coursesForShow) @@ -228,15 +237,10 @@ class PersistentCourseListPresenter } @WorkerThread - private fun sortByLastAction(courses: List): MutableList { - val progressIds = courses.mapNotNull { - it.progress - } - val courseProgressesMap = databaseFacade.getProgresses(progressIds).associateBy { it.id } - + private fun sortByLastAction(courses: List, idProgressesMap: Map): MutableList { return courses.sortedWith(Comparator { course1, course2 -> - val progress1: Progress? = courseProgressesMap[course1.progress] - val progress2: Progress? = courseProgressesMap[course2.progress] + val progress1: Progress? = idProgressesMap[course1.progress] + val progress2: Progress? = idProgressesMap[course2.progress] val lastViewed1 = progress1?.lastViewed?.toLongOrNull() val lastViewed2 = progress2?.lastViewed?.toLongOrNull() @@ -257,6 +261,22 @@ class PersistentCourseListPresenter }).toMutableList() } + @WorkerThread + private fun getProgressesFromDb(courses: List): Map { + val progressIds = courses.mapNotNull { + it.progress + } + return databaseFacade.getProgresses(progressIds).associateBy { it.id } + } + + private fun applyProgressesToCourses(progresses: Map, courses: List) { + courses.forEach { course -> + progresses[course.progress]?.let { + course.progressObject = it + } + } + } + fun loadMore(courseType: Table, needFilter: Boolean) { downloadData(courseType, needFilter, isRefreshing = false, isLoadMore = true) } diff --git a/app/src/main/java/org/stepic/droid/model/Course.java b/app/src/main/java/org/stepic/droid/model/Course.java index 09653e5359..2de1a5ab30 100644 --- a/app/src/main/java/org/stepic/droid/model/Course.java +++ b/app/src/main/java/org/stepic/droid/model/Course.java @@ -69,10 +69,20 @@ public final class Course implements Parcelable { @Nullable private String progress; + private Progress progressObject; + public Course() { } + public Progress getProgressObject() { + return progressObject; + } + + public void setProgressObject(Progress progressObject) { + this.progressObject = progressObject; + } + @Nullable public String getProgress() { return progress; @@ -352,6 +362,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(lastStepId); dest.writeLong(learnersCount); dest.writeString(progress); + dest.writeParcelable(progressObject, flags); } protected Course(Parcel in) { @@ -392,6 +403,7 @@ protected Course(Parcel in) { lastStepId = in.readString(); learnersCount = in.readLong(); progress = in.readString(); + progressObject = in.readParcelable(Progress.class.getClassLoader()); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/org/stepic/droid/model/Progress.kt b/app/src/main/java/org/stepic/droid/model/Progress.kt index 4fb2296fa4..e9c2eb907b 100644 --- a/app/src/main/java/org/stepic/droid/model/Progress.kt +++ b/app/src/main/java/org/stepic/droid/model/Progress.kt @@ -1,5 +1,7 @@ package org.stepic.droid.model +import android.os.Parcel +import android.os.Parcelable import com.google.gson.annotations.SerializedName data class Progress( @@ -14,4 +16,32 @@ data class Progress( val nStepsPassed: Int = 0, @SerializedName("is_passed") val isPassed: Boolean = false -) +) : Parcelable { + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(id) + parcel.writeString(lastViewed) + parcel.writeString(score) + parcel.writeInt(cost) + parcel.writeInt(nSteps) + parcel.writeInt(nStepsPassed) + parcel.writeByte(if (isPassed) 1 else 0) + } + + override fun describeContents(): Int = 0 + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Progress = Progress( + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readByte() != 0.toByte() + ) + + override fun newArray(size: Int): Array = arrayOfNulls(size) + } + +} diff --git a/app/src/test/java/org/stepic/droid/model/ProgressTest.kt b/app/src/test/java/org/stepic/droid/model/ProgressTest.kt new file mode 100644 index 0000000000..5309437caa --- /dev/null +++ b/app/src/test/java/org/stepic/droid/model/ProgressTest.kt @@ -0,0 +1,16 @@ +package org.stepic.droid.model + +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.stepic.droid.testUtils.assertThatObjectParcelable + +@RunWith(RobolectricTestRunner::class) +class ProgressTest { + + @Test + fun progressIsParcelable() { + val progress = Progress(id = "76-2222", score = "227", cost = 337) + progress.assertThatObjectParcelable() + } +} From 128f131e855a211d20342e790c82dd3b197a0a32 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 15:37:18 +0300 Subject: [PATCH 015/140] show prgresses of courses in My courses --- .../java/org/stepic/droid/model/Course.java | 1 + .../stepic/droid/services/LoadService.java | 4 +- .../view_hoders/CourseItemViewHolder.kt | 41 +++++++++++-------- .../droid/ui/custom/CircleProgressView.kt | 4 ++ .../stepic/droid/ui/util/ViewExtensions.kt | 9 ++++ .../org/stepic/droid/util/ProgressUtil.java | 17 -------- .../org/stepic/droid/util/ProgressUtil.kt | 29 +++++++++++++ 7 files changed, 70 insertions(+), 35 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/util/ProgressUtil.java create mode 100644 app/src/main/java/org/stepic/droid/util/ProgressUtil.kt diff --git a/app/src/main/java/org/stepic/droid/model/Course.java b/app/src/main/java/org/stepic/droid/model/Course.java index 2de1a5ab30..765902a681 100644 --- a/app/src/main/java/org/stepic/droid/model/Course.java +++ b/app/src/main/java/org/stepic/droid/model/Course.java @@ -75,6 +75,7 @@ public Course() { } + @Nullable public Progress getProgressObject() { return progressObject; } diff --git a/app/src/main/java/org/stepic/droid/services/LoadService.java b/app/src/main/java/org/stepic/droid/services/LoadService.java index ed2576ddbe..7e55d79644 100644 --- a/app/src/main/java/org/stepic/droid/services/LoadService.java +++ b/app/src/main/java/org/stepic/droid/services/LoadService.java @@ -244,7 +244,7 @@ private void addLesson(Lesson lessonOut, long sectionId) { databaseFacade.addAssignment(item); } - String[] ids = ProgressUtil.getAllProgresses(assignments); + String[] ids = ProgressUtil.INSTANCE.getAllProgresses(assignments); List progresses = fetchProgresses(ids); for (Progress item : progresses) { databaseFacade.addProgress(item); @@ -319,7 +319,7 @@ private void addSection(Section sectionOut) { if (responseIsSuccess) { long[] lessonsIds = StepikLogicHelper.fromUnitsToLessonIds(units); - List progresses = fetchProgresses(ProgressUtil.getAllProgresses(units)); + List progresses = fetchProgresses(ProgressUtil.INSTANCE.getAllProgresses(units)); for (Progress item : progresses) { databaseFacade.addProgress(item); } diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt index aff428a6c4..385c2dc45f 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt @@ -22,10 +22,8 @@ import org.stepic.droid.core.presenters.ContinueCoursePresenter import org.stepic.droid.core.presenters.DroppingPresenter import org.stepic.droid.model.Course import org.stepic.droid.model.CoursesCarouselColorType -import org.stepic.droid.util.ColorUtil -import org.stepic.droid.util.ContextMenuCourseUtil -import org.stepic.droid.util.StepikLogicHelper -import org.stepic.droid.util.SuppressFBWarnings +import org.stepic.droid.ui.util.changeVisibility +import org.stepic.droid.util.* import java.util.* import javax.inject.Inject @@ -193,12 +191,11 @@ class CourseItemViewHolder( .fitCenter() .into(imageViewTarget) - if (course.learnersCount > 0) { + val needShowLearners = course.learnersCount > 0 + if (needShowLearners) { learnersCountText.text = String.format(Locale.getDefault(), "%d", course.learnersCount) - learnersCountContainer.visibility = View.VISIBLE - } else { - learnersCountContainer.visibility = View.GONE } + learnersCountContainer.changeVisibility(needShowLearners) if (isEnrolled(course)) { @@ -209,16 +206,28 @@ class CourseItemViewHolder( showJoinButton() } - val progressPart = (position % 10).toFloat() / 10f - courseItemProgress.progress = progressPart - courseItemProgressTitle.text = "%.2f%%".format(progressPart * 100) + changeProgressView(course) + courseItemMore.changeVisibility(showMore) + } - courseItemMore.visibility = if (showMore) { - View.VISIBLE - } else { - View.GONE - } + private fun changeProgressView(course: Course) { + val progressPercent: Int? = ProgressUtil.getProgressPercent(course.progressObject) + val needShow: Boolean = + if (progressPercent != null && progressPercent > 0) { + + // title and image should be equal + courseItemProgress.progress = progressPercent / 100f + courseItemProgressTitle.text = itemView + .context + .resources + .getString(R.string.percent_symbol, progressPercent) + true + } else { + false + } + courseItemProgress.changeVisibility(needShow) + courseItemProgressTitle.changeVisibility(needShow) } private fun isEnrolled(course: Course?): Boolean = diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt index d4d036e227..1b611ea8c2 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt @@ -27,6 +27,10 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: } var progress: Float = 0.0f + set (value) { + field = value + invalidate() + } private val strokeBound = DpPixelsHelper.convertDpToPixel(5f) //if < 5dp -> onDraw with space, >= 5dp -> without spaces diff --git a/app/src/main/java/org/stepic/droid/ui/util/ViewExtensions.kt b/app/src/main/java/org/stepic/droid/ui/util/ViewExtensions.kt index 84a82769e9..2a4a97f321 100644 --- a/app/src/main/java/org/stepic/droid/ui/util/ViewExtensions.kt +++ b/app/src/main/java/org/stepic/droid/ui/util/ViewExtensions.kt @@ -1,6 +1,7 @@ package org.stepic.droid.ui.util import android.os.Build +import android.view.View import android.view.ViewTreeObserver @@ -12,3 +13,11 @@ fun ViewTreeObserver.removeGlobalLayoutListener(listener: ViewTreeObserver.OnGlo removeGlobalOnLayoutListener(listener) } } + +fun View.changeVisibility(needShow: Boolean) { + if (needShow) { + this.visibility = View.VISIBLE + } else { + this.visibility = View.GONE + } +} diff --git a/app/src/main/java/org/stepic/droid/util/ProgressUtil.java b/app/src/main/java/org/stepic/droid/util/ProgressUtil.java deleted file mode 100644 index d18222e859..0000000000 --- a/app/src/main/java/org/stepic/droid/util/ProgressUtil.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.stepic.droid.util; - -import org.stepic.droid.model.IProgressable; - -import java.util.ArrayList; -import java.util.List; - -public class ProgressUtil { - public static String[] getAllProgresses(List objects) { - - List progressesId = new ArrayList<>(); - for (IProgressable item : objects) { - progressesId.add(item.getProgressId()); - } - return progressesId.toArray(new String[progressesId.size()]); - } -} diff --git a/app/src/main/java/org/stepic/droid/util/ProgressUtil.kt b/app/src/main/java/org/stepic/droid/util/ProgressUtil.kt new file mode 100644 index 0000000000..7b92c49173 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/util/ProgressUtil.kt @@ -0,0 +1,29 @@ +package org.stepic.droid.util + +import org.stepic.droid.model.IProgressable +import org.stepic.droid.model.Progress + +object ProgressUtil { + fun getAllProgresses(objects: List?): Array { + return objects + ?.mapNotNull { it.getProgressId() } + ?.toTypedArray() + ?: emptyArray() + } + + fun getProgressPercent(progress: Progress?): Int? { + if (progress == null) { + return null + } + + val score: Double? = progress.score?.let { StringUtil.safetyParseString(it) } + val cost = progress.cost + return if (score != null) { + val progressPart: Double = score / cost + val progressShow: Int = (progressPart * 100).toInt() + progressShow + } else { + null + } + } +} From 214e759a9bcf8c15c1f07c91204466c3244067d9 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 16:11:25 +0300 Subject: [PATCH 016/140] add ic_rating for course widget --- app/src/main/res/drawable-hdpi/ic_rating.png | Bin 0 -> 538 bytes app/src/main/res/drawable-mdpi/ic_rating.png | Bin 0 -> 320 bytes app/src/main/res/drawable-xhdpi/ic_rating.png | Bin 0 -> 728 bytes app/src/main/res/drawable-xxhdpi/ic_rating.png | Bin 0 -> 1048 bytes app/src/main/res/drawable-xxxhdpi/ic_rating.png | Bin 0 -> 1594 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_rating.png create mode 100644 app/src/main/res/drawable-mdpi/ic_rating.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_rating.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_rating.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_rating.png diff --git a/app/src/main/res/drawable-hdpi/ic_rating.png b/app/src/main/res/drawable-hdpi/ic_rating.png new file mode 100644 index 0000000000000000000000000000000000000000..4cad24d751cd737173549984085bee038d4b8a71 GIT binary patch literal 538 zcmV+#0_FXQP)gcJ%h<3jKgX5JveCP3$jXq{;5YEVmokYdq2PGp=N8~eH1 zXf(Qx<7Sveis*YsO1URgf3nbu!|ERy?2ce^a?Xm!y>rQAf304x_ag7fu+VX4Pid`Q z0-SBNs_!F1CMM?1Wb#wovP_{hKL#id@GBuG*Y6K>I&JnUmCEl>JNbP1jA^0@AOpbM z75`nfcL2?{T94k2%%o7bbx8>LQ=A+UZ!q)CcDwol0FQ+DmQtxNzWCyA$ta~P&ovzU~LVl;@bYTAuUHo0y14_GW;5@s<76Yd0yYvVf>)aVrjn?bZ0 z)F4*t-Mw-_+2HQ2@596I_YjDpM4w-&wc>?Lu8U|w}W+6vnRq1m@8Ge zaqj%B0`6Uc`oJ9UrOK&u;YlgnY6VSWOkadmRk_ad%*OG>YlXSfP?cR^9{9|%+UhAJ<>opWJWm3bfJ z2v}0(T~&|cIEpIP=xrI3_d&Kn??pHqjiQGNb9V(~Q-p6-7V~`ODUJvK)BOS(fn^Mv S#9?Uw0000GT6vw~s&FGe9rbUrpe^>+|h(L@84CxXCi@P%pT|_*%tB20vA!sfUUM!MS#twl= z!H-!%*o&t(G0+mlAaUcos`%FL0KNj4-Py@audFO&1A)DyXmtFdqPQl2s{lg(gi->u zNrVUO?RaQeR?%kI7lfGEtpyJPCS8w@0yN{nq{KurX-(By zM8056i}wO_9gtl_I0Vpn0B82P+ydlVfU-nbC&G#l){8(-Iu;u~${f=6JlqLTWdq*Y z+yr>CSS*R<<;ULwfxRTdNVGZ*3;_3taI8Z3(=$juuPmlgv)gs-ijgCV()b2ISA}@p zb#s@OmKMI(<>Odv{5Z4w3P895upwpWN-{a^tY$ z{6Ny`>_!8@2Q%HBl(rUPEnDk@d8mjeRQ#az3$-?}rp@doJNL+#RHbBhc4pbm>)dny zzkB{?&bdRV;EBcb4%Zb0+fJRRU>i`_;GUj=mAPC##f;l!8FyKhc`@u>p&>L)zefm6 z0B8bOPp6Z~YYjn)k{BhT-bG=~3L)>b?YDjp0}?b7)YbC$m4xrh`j-Q3#9@|cy^b^1GzHA6DpsOo!9}&Gzgd2(o%oE{pqM3Is%W|s% zp{j}70QwNXx*`I3fP2&FL58XcMbY0T;sih+G2>~+iG0=4k{9RCi;a>*20+~a z9m(aS-lInk%#@prKz77pyI%m@DWZ!C)6~p z4uD&=ucO@b23;2@6U%L`DE&8OG6%j7D*XTT6+!g%4PG}pJNI#+Q1j5CL;HUW3sMOL zsj5Bz;0cLVs`brGAGFu%K|5Q?HdLWFk!L;!fB zdN7?fhpPf%7=|=8^-W`AV_gKOtuGX6qLP$f0mvx;cl;;H-%1ic49Je_7B0(j!(3e* z@~y2+m;7wZKJpV0eiMSv0b(eV897(c zrDp3^qh`&TUv@F$RR9eE(w%3LeK5FxdCHTITs zw+salkH@2PbM+$tb{6-e%A;J<_O2CTVH}|L5=HTuB%#Z)%pd#;CsZa>b$2Vk9{|`0 zU>3lnBrOaHQTq&lP5>(b@6&W2um(`qg=M|wTrIMF`#_|jVd2*K`J8k3@aUOxA^rxpk$5qh SXJ-Kb0000dV`uBddxR1Odg! zwg4lJ#h7nv$;gbss0)c=j3ycp#RMWmhk!UPW32u9o!1;Tbb_IFo?04OmIgsS${Ck;lX?cjK|~Zn{W2VL}ZQ#-b^MNTLDNubL15` z9DeW`Qq_@+0;pFi{k&~&{N;ZMJauY3SW)qFwFqAzF&e;kBqn-+p_v&~i->XhN&o>5iBkZ-0I=-v;nWA6og4c+eCI4lPQd+6 zKUC(rnYpGp02u2b`A!jC7YK}Rx9zxbI;W8{u*nvQ)Z9jLIe_c4XP5Vs3NEqjwO?k} z4z2iCz|m;UY=CP3T<8JfD-w%aTN}4}&<-id8Q8L{kk%t>0KN`za1Ec{ot+u`Aizi4 z+8W;ZkAUyLz;z2ACGqqifFmMi(<27%5&%~KDC_^689<&;s=MB{?Q>tl;c(4F63>{H zOyZaU1+Yyi=}4zDdkPAIlSR~>fK(2EmjHN0DQBf^Hyz5=<(x|*8jam7f~QH0C9zFw zdB3>0=<~sCcFvsG=yV#DfZPGF65w{nab9b0->~bP16$U-Nm|RTr0hOWZQ6puvNE^8w%_XUn%S(~rKP=@jT>`o8aa15 zuYkj$%h}=KfbkM@Sb!su*r`^XNHp&E0^vuKcVNqUtk`u=m_0_J>z1@^-n{yVAE0d7 zVE~>##dY21NRA-6q_wraGaH1T&+`gAeR`}U6p~sIK4lyRxT>#Dt^TJa&ktn`n)-O`|VYwWo5;+1AB{60||QoS*etM-L}{NmJjHB z0W%za;1;C{>iXO8pM%79*VT2CCy)Qo&v8C44x3J;b$SBHi?n9B2rnk(G7_TzxftM8 z07jmX%p5XzipYIP&lz`Y{UO{y-X^d8%8JnGebUk*p3^KJlSA%JUuQ&H5{ZUw!vbts5027WnG>^tp6E5n5W1fLS>-s=(%!z#T(Ec= zz8p3YXU@Fue5HzJlKM#ilRRZPTeKIz3ZDHT|1+iTDLna%)4qt(}ujEgYr5%^=J_>65gZ1<=?OZKlE zo;9m>s@Co@k~f*iB(#X^Alam~qz7*0&4fHv-{wvjz~hNTW5<64JTD?5ZvZei^1Dbh zI8LxF6gqUEyu4hxyVDg~7fc6eCgyb{PKvO$t*v3xIR`cmV|MK5dO!q=M5HO5W=l`c z4_%#|ou&oj-!iGsno%(TfILf82oSi4yZL)OA^u(TL1t607*qoM6N<$f)!fuEdT%j literal 0 HcmV?d00001 From 1f54b6a6ce79341a91b35a24a29be66e4a15e24e Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Fri, 3 Nov 2017 16:17:48 +0300 Subject: [PATCH 017/140] return action bar size back to default --- app/src/main/res/layout/view_centered_toolbar.xml | 2 +- app/src/main/res/values/dimens.xml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/res/layout/view_centered_toolbar.xml b/app/src/main/res/layout/view_centered_toolbar.xml index 05fd35de49..cbe5f12ff1 100644 --- a/app/src/main/res/layout/view_centered_toolbar.xml +++ b/app/src/main/res/layout/view_centered_toolbar.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/centeredToolbar" android:layout_width="match_parent" - android:layout_height="@dimen/action_bar_height" + android:layout_height="?attr/actionBarSize" android:layout_gravity="center" app:titleTextAppearance="@style/StepikToolbarTextAppearance"> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 873d2378cc..655dc7011c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -143,6 +143,4 @@ 8dp 12dp 16dp - - 60dp From 06b58a6f4ec6facd19acc94fcce2fe4b54618d3b Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 16:28:28 +0300 Subject: [PATCH 018/140] add rating to database and to course object --- .../java/org/stepic/droid/model/Course.java | 26 +++--- .../stepic/droid/storage/DatabaseHelper.java | 13 +++ .../stepic/droid/storage/dao/CourseDaoImpl.kt | 90 +++++++------------ .../droid/storage/structure/DatabaseInfo.kt | 2 +- ...DbStructureEnrolledAndFeaturedCourses.java | 2 + .../org/stepic/droid/util/CursorExtensions.kt | 5 +- 6 files changed, 63 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/model/Course.java b/app/src/main/java/org/stepic/droid/model/Course.java index 765902a681..ad0709630e 100644 --- a/app/src/main/java/org/stepic/droid/model/Course.java +++ b/app/src/main/java/org/stepic/droid/model/Course.java @@ -42,8 +42,6 @@ public final class Course implements Parcelable { @SerializedName("certificate_link") private String certificateLink; private String title; - @SerializedName("begin_date_source") - private String beginDateSource; @SerializedName("last_deadline") private String lastDeadline; @SerializedName("begin_date") @@ -70,11 +68,21 @@ public final class Course implements Parcelable { private String progress; private Progress progressObject; + private double rating; public Course() { } + public double getRating() { + return rating; + } + + public void setRating(double rating) { + this.rating = rating; + } + + @Nullable public Progress getProgressObject() { return progressObject; @@ -266,10 +274,6 @@ public void setTitle(String title) { this.title = title; } - public void setBeginDateSource(String beginDateSource) { - this.beginDateSource = beginDateSource; - } - public void setLastDeadline(String lastDeadline) { this.lastDeadline = lastDeadline; } @@ -282,10 +286,6 @@ public void setSlug(String slug) { this.slug = slug; } - public String getBeginDateSource() { - return beginDateSource; - } - public String getLastDeadline() { return lastDeadline; } @@ -303,7 +303,7 @@ public long[] getSections() { return sections; } - public void setSections(long[] sections) { + public void setSections(@Nullable long[] sections) { this.sections = sections; } @@ -349,7 +349,6 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeByte(isActive ? (byte) 1 : (byte) 0); dest.writeString(this.certificateLink); dest.writeString(this.title); - dest.writeString(this.beginDateSource); dest.writeString(this.lastDeadline); dest.writeString(this.language); dest.writeByte(isPublic ? (byte) 1 : (byte) 0); @@ -364,6 +363,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(learnersCount); dest.writeString(progress); dest.writeParcelable(progressObject, flags); + dest.writeDouble(rating); } protected Course(Parcel in) { @@ -390,7 +390,6 @@ protected Course(Parcel in) { this.isActive = in.readByte() != 0; this.certificateLink = in.readString(); this.title = in.readString(); - this.beginDateSource = in.readString(); this.lastDeadline = in.readString(); this.language = in.readString(); this.isPublic = in.readByte() != 0; @@ -405,6 +404,7 @@ protected Course(Parcel in) { learnersCount = in.readLong(); progress = in.readString(); progressObject = in.readParcelable(Progress.class.getClassLoader()); + rating = in.readDouble(); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java b/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java index 56aa738cf0..a7df540a7f 100644 --- a/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java +++ b/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java @@ -31,6 +31,7 @@ public final class DatabaseHelper extends SQLiteOpenHelper { private static final String LONG_TYPE = "LONG"; private static final String INT_TYPE = "INTEGER"; private static final String BOOLEAN_TYPE = "BOOLEAN"; + private static final String REAL_TYPE = "REAL"; private static final String WHITESPACE = " "; private static final String FALSE_VALUE = "0"; private static final String TRUE_VALUE = "1"; @@ -86,8 +87,10 @@ public void onCreate(SQLiteDatabase db) { upgradeFrom25To26(db); upgradeFrom26To27(db); upgradeFrom27To28(db); + upgradeFrom28To29(db); } + @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < 2) { @@ -240,6 +243,16 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { upgradeFrom27To28(db); } + if (oldVersion < 29) { + upgradeFrom28To29(db); + } + + } + + + private void upgradeFrom28To29(SQLiteDatabase db) { + alterColumn(db, DbStructureEnrolledAndFeaturedCourses.ENROLLED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, REAL_TYPE); + alterColumn(db, DbStructureEnrolledAndFeaturedCourses.FEATURED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, REAL_TYPE); } private void upgradeFrom27To28(SQLiteDatabase db) { diff --git a/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt b/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt index 42cc304e11..970901a024 100644 --- a/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt +++ b/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt @@ -9,8 +9,7 @@ import org.stepic.droid.storage.operations.CrudOperations import org.stepic.droid.storage.structure.DbStructureCachedVideo import org.stepic.droid.storage.structure.DbStructureEnrolledAndFeaturedCourses import org.stepic.droid.storage.structure.DbStructureVideoUrl -import org.stepic.droid.util.DbParseHelper -import org.stepic.droid.util.transformToCachedVideo +import org.stepic.droid.util.* import javax.inject.Inject class CourseDaoImpl @Inject @@ -23,66 +22,37 @@ constructor( public override fun parsePersistentObject(cursor: Cursor): Course { val course = Course() - - val indexId = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.COURSE_ID) - val indexSummary = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.SUMMARY) - val indexCover = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.COVER_LINK) - val indexIntro = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.INTRO_LINK_VIMEO) - val indexTitle = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.TITLE) - val indexLanguage = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.LANGUAGE) - val indexBeginDateSource = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.BEGIN_DATE_SOURCE) - val indexBeginDate = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.BEGIN_DATE) - val indexEndDate = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.END_DATE) - val indexLastDeadline = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.LAST_DEADLINE) - val indexDescription = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.DESCRIPTION) - val indexInstructors = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.INSTRUCTORS) - val indexRequirements = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.REQUIREMENTS) - val indexEnrollment = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.ENROLLMENT) - val indexSection = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.SECTIONS) - val indexWorkload = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.WORKLOAD) - val indexCourseFormat = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.COURSE_FORMAT) - val indexTargetAudience = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.TARGET_AUDIENCE) - val indexCertificate = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.CERTIFICATE) - val indexIntroVideoId = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.INTRO_VIDEO_ID) - val indexSlug = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.SLUG) - val indexScheduleLink = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.SCHEDULE_LINK) - val indexScheduleLongLink = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.SCHEDULE_LONG_LINK) - val indexLastStepId = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.LAST_STEP_ID) - val indexIsActive = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.IS_ACTIVE) - val indexLearnersCount = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.LEARNERS_COUNT) - val indexProgress = cursor.getColumnIndex(DbStructureEnrolledAndFeaturedCourses.Column.PROGRESS) - - course.lastStepId = cursor.getString(indexLastStepId) - course.certificate = cursor.getString(indexCertificate) - course.workload = cursor.getString(indexWorkload) - course.courseFormat = cursor.getString(indexCourseFormat) - course.targetAudience = cursor.getString(indexTargetAudience) - - course.setId(cursor.getLong(indexId)) - course.summary = cursor.getString(indexSummary) - course.cover = cursor.getString(indexCover) - course.intro = cursor.getString(indexIntro) - course.title = cursor.getString(indexTitle) - course.language = cursor.getString(indexLanguage) - course.beginDateSource = cursor.getString(indexBeginDateSource) - course.lastDeadline = cursor.getString(indexLastDeadline) - course.description = cursor.getString(indexDescription) - course.instructors = DbParseHelper.parseStringToLongArray(cursor.getString(indexInstructors)) - course.requirements = cursor.getString(indexRequirements) - course.enrollment = cursor.getInt(indexEnrollment) - course.sections = DbParseHelper.parseStringToLongArray(cursor.getString(indexSection)) - course.introVideoId = cursor.getLong(indexIntroVideoId) - course.slug = cursor.getString(indexSlug) - course.scheduleLink = cursor.getString(indexScheduleLink) - course.scheduleLongLink = cursor.getString(indexScheduleLongLink) - course.beginDate = cursor.getString(indexBeginDate) - course.endDate = cursor.getString(indexEndDate) - course.learnersCount = cursor.getLong(indexLearnersCount) - course.progress = cursor.getString(indexProgress) + course.lastStepId = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.LAST_STEP_ID) + course.certificate = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.CERTIFICATE) + course.workload = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.WORKLOAD) + course.courseFormat = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.COURSE_FORMAT) + course.targetAudience = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.TARGET_AUDIENCE) + + course.setId(cursor.getLong(DbStructureEnrolledAndFeaturedCourses.Column.COURSE_ID)) + course.summary = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.SUMMARY) + course.cover = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.COVER_LINK) + course.intro = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.INTRO_LINK_VIMEO) + course.title = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.TITLE) + course.language = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.LANGUAGE) + course.lastDeadline = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.LAST_DEADLINE) + course.description = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.DESCRIPTION) + course.instructors = DbParseHelper.parseStringToLongArray(cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.INSTRUCTORS)) + course.requirements = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.REQUIREMENTS) + course.enrollment = cursor.getInt(DbStructureEnrolledAndFeaturedCourses.Column.ENROLLMENT) + course.sections = DbParseHelper.parseStringToLongArray(cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.SECTIONS)) + course.introVideoId = cursor.getLong(DbStructureEnrolledAndFeaturedCourses.Column.INTRO_VIDEO_ID) + course.slug = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.SLUG) + course.scheduleLink = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.SCHEDULE_LINK) + course.scheduleLongLink = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.SCHEDULE_LONG_LINK) + course.beginDate = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.BEGIN_DATE) + course.endDate = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.END_DATE) + course.learnersCount = cursor.getLong(DbStructureEnrolledAndFeaturedCourses.Column.LEARNERS_COUNT) + course.progress = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.PROGRESS) + course.rating = cursor.getDouble(DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING) var isActive = true try { - isActive = cursor.getInt(indexIsActive) > 0 + isActive = cursor.getInt(DbStructureEnrolledAndFeaturedCourses.Column.IS_ACTIVE) > 0 } catch (exception: Exception) { //it can be null before migration --> default active } @@ -102,7 +72,6 @@ constructor( values.put(DbStructureEnrolledAndFeaturedCourses.Column.INTRO_LINK_VIMEO, course.intro) values.put(DbStructureEnrolledAndFeaturedCourses.Column.TITLE, course.title) values.put(DbStructureEnrolledAndFeaturedCourses.Column.LANGUAGE, course.language) - values.put(DbStructureEnrolledAndFeaturedCourses.Column.BEGIN_DATE_SOURCE, course.beginDateSource) values.put(DbStructureEnrolledAndFeaturedCourses.Column.LAST_DEADLINE, course.lastDeadline) values.put(DbStructureEnrolledAndFeaturedCourses.Column.DESCRIPTION, course.description) @@ -129,6 +98,7 @@ constructor( values.put(DbStructureEnrolledAndFeaturedCourses.Column.IS_ACTIVE, course.isActive) values.put(DbStructureEnrolledAndFeaturedCourses.Column.LEARNERS_COUNT, course.learnersCount) values.put(DbStructureEnrolledAndFeaturedCourses.Column.PROGRESS, course.progress) + values.put(DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, course.rating) val video = course.introVideo if (video != null) { diff --git a/app/src/main/java/org/stepic/droid/storage/structure/DatabaseInfo.kt b/app/src/main/java/org/stepic/droid/storage/structure/DatabaseInfo.kt index e171bea3cb..d7fbfb1485 100644 --- a/app/src/main/java/org/stepic/droid/storage/structure/DatabaseInfo.kt +++ b/app/src/main/java/org/stepic/droid/storage/structure/DatabaseInfo.kt @@ -2,5 +2,5 @@ package org.stepic.droid.storage.structure object DatabaseInfo { const val FILE_NAME = "stepic_database.db" - const val VERSION = 28 + const val VERSION = 29 } diff --git a/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java b/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java index 311dc72c89..fc6adf3488 100644 --- a/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java +++ b/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java @@ -27,6 +27,7 @@ public static final class Column { public static final String IS_PUBLIC = "is_public"; public static final String TITLE = "title"; public static final String SLUG = "slug"; + @Deprecated public static final String BEGIN_DATE_SOURCE = "begin_date_source"; public static final String BEGIN_DATE = "begin_date"; public static final String LAST_DEADLINE = "last_deadline"; @@ -41,5 +42,6 @@ public static final class Column { public static final String IS_ACTIVE = "is_active"; public static final String LEARNERS_COUNT = "learners_count"; public static final String PROGRESS = "progress"; + public static final String AVERAGE_RATING = "average_rating"; } } diff --git a/app/src/main/java/org/stepic/droid/util/CursorExtensions.kt b/app/src/main/java/org/stepic/droid/util/CursorExtensions.kt index 230c6271a4..133cd6ba3f 100644 --- a/app/src/main/java/org/stepic/droid/util/CursorExtensions.kt +++ b/app/src/main/java/org/stepic/droid/util/CursorExtensions.kt @@ -13,4 +13,7 @@ fun Cursor.getLong(columnName: String): Long = this.getLong(this.getColumnIndexOrThrow(columnName)) fun Cursor.getInt(columnName: String): Int = - this.getInt(this.getColumnIndexOrThrow(columnName)) \ No newline at end of file + this.getInt(this.getColumnIndexOrThrow(columnName)) + +fun Cursor.getDouble(columnName: String) : Double = + this.getDouble(this.getColumnIndexOrThrow(columnName)) \ No newline at end of file From 1a7e3f83ccbc36f832d4a4905703d34f21df64ed Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 16:38:31 +0300 Subject: [PATCH 019/140] Rename meta response add reviews to API. --- .../core/presenters/CertificatePresenter.kt | 10 ++++----- .../PersistentCourseListPresenter.kt | 4 ++-- .../stepic/droid/model/CourseReviewSummary.kt | 3 +++ .../stepic/droid/services/LoadService.java | 4 ++-- .../main/java/org/stepic/droid/web/Api.java | 18 +++++++++------- .../java/org/stepic/droid/web/ApiImpl.java | 21 ++++++++++++------- .../stepic/droid/web/AssignmentResponse.java | 2 +- .../stepic/droid/web/CourseListsResponse.kt | 2 +- .../stepic/droid/web/CourseReviewResponse.kt | 8 +++++++ ...Response.java => CoursesMetaResponse.java} | 4 ++-- .../org/stepic/droid/web/IStepicResponse.java | 6 ------ .../org/stepic/droid/web/MetaResponseBase.kt | 5 +++++ .../droid/web/NotificationResponse.java | 2 +- .../stepic/droid/web/ProgressesResponse.java | 2 +- .../droid/web/SearchResultResponse.java | 2 +- ...esponse.java => SectionsMetaResponse.java} | 4 ++-- .../org/stepic/droid/web/SignUpResponse.java | 4 ---- .../java/org/stepic/droid/web/StepResponse.kt | 2 +- .../stepic/droid/web/StepicResponseBase.java | 16 -------------- .../droid/web/StepicRestLoggedService.java | 19 ++++++++++------- ...picResponse.java => UnitMetaResponse.java} | 4 ++-- .../stepic/droid/web/UserStepicResponse.java | 19 ----------------- .../org/stepic/droid/web/UsersResponse.kt | 9 ++++++++ .../presenters/InstructorsPresenterTest.java | 6 +++--- .../core/presenters/ProfilePresenterTest.java | 4 ++-- .../SearchCoursesPresenterTest.java | 4 ++-- 26 files changed, 87 insertions(+), 97 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt create mode 100644 app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt rename app/src/main/java/org/stepic/droid/web/{CoursesStepicResponse.java => CoursesMetaResponse.java} (69%) delete mode 100644 app/src/main/java/org/stepic/droid/web/IStepicResponse.java create mode 100644 app/src/main/java/org/stepic/droid/web/MetaResponseBase.kt rename app/src/main/java/org/stepic/droid/web/{SectionsStepicResponse.java => SectionsMetaResponse.java} (69%) delete mode 100644 app/src/main/java/org/stepic/droid/web/SignUpResponse.java delete mode 100644 app/src/main/java/org/stepic/droid/web/StepicResponseBase.java rename app/src/main/java/org/stepic/droid/web/{UnitStepicResponse.java => UnitMetaResponse.java} (70%) delete mode 100644 app/src/main/java/org/stepic/droid/web/UserStepicResponse.java create mode 100644 app/src/main/java/org/stepic/droid/web/UsersResponse.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CertificatePresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/CertificatePresenter.kt index 3503031e04..e0ee0d4cc1 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/CertificatePresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/CertificatePresenter.kt @@ -14,7 +14,7 @@ import org.stepic.droid.preferences.SharedPreferenceHelper import org.stepic.droid.storage.operations.DatabaseFacade import org.stepic.droid.web.Api import org.stepic.droid.web.CertificateResponse -import org.stepic.droid.web.CoursesStepicResponse +import org.stepic.droid.web.CoursesMetaResponse import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -36,7 +36,7 @@ class CertificatePresenter private var certificateViewItemList: ArrayList? = null private var certificatesCall: Call? = null - private var coursesCall: Call? = null + private var coursesCall: Call? = null @MainThread fun showCertificates(isRefreshing: Boolean) { @@ -102,13 +102,13 @@ class CertificatePresenter .associateBy { it.course!! } val baseUrl = config.baseUrl coursesCall = api.getCourses(1, courseIds) - coursesCall?.enqueue(object : Callback { + coursesCall?.enqueue(object : Callback { - override fun onFailure(call: Call?, t: Throwable?) { + override fun onFailure(call: Call?, t: Throwable?) { view?.onInternetProblem() } - override fun onResponse(call: Call?, response: Response?) { + override fun onResponse(call: Call?, response: Response?) { if (response?.isSuccessful == true) { val localCertificateViewItems: List = response .body() diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt index 7df2e213e4..1c0a47ddbe 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt @@ -15,7 +15,7 @@ import org.stepic.droid.storage.operations.DatabaseFacade import org.stepic.droid.storage.operations.Table import org.stepic.droid.util.RWLocks import org.stepic.droid.web.Api -import org.stepic.droid.web.CoursesStepicResponse +import org.stepic.droid.web.CoursesMetaResponse import timber.log.Timber import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger @@ -188,7 +188,7 @@ class PersistentCourseListPresenter } } - private fun handleMeta(response: CoursesStepicResponse) { + private fun handleMeta(response: CoursesMetaResponse) { hasNextPage.set(response.meta.has_next) if (hasNextPage.get()) { currentPage.set(response.meta.page + 1) // page for next loading diff --git a/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt b/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt new file mode 100644 index 0000000000..919cd12517 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt @@ -0,0 +1,3 @@ +package org.stepic.droid.model + +data class CourseReviewSummary(val average: Double) diff --git a/app/src/main/java/org/stepic/droid/services/LoadService.java b/app/src/main/java/org/stepic/droid/services/LoadService.java index 7e55d79644..78dbbaba80 100644 --- a/app/src/main/java/org/stepic/droid/services/LoadService.java +++ b/app/src/main/java/org/stepic/droid/services/LoadService.java @@ -33,7 +33,7 @@ import org.stepic.droid.web.LessonStepicResponse; import org.stepic.droid.web.ProgressesResponse; import org.stepic.droid.web.StepResponse; -import org.stepic.droid.web.UnitStepicResponse; +import org.stepic.droid.web.UnitMetaResponse; import java.io.File; import java.io.IOException; @@ -307,7 +307,7 @@ private void addSection(Section sectionOut) { while (responseIsSuccess && pointer < unitIds.length) { int lastExclusive = Math.min(unitIds.length, pointer + AppConstants.DEFAULT_NUMBER_IDS_IN_QUERY); long[] subArrayForLoading = Arrays.copyOfRange(unitIds, pointer, lastExclusive); - Response unitResponse = api.getUnits(subArrayForLoading).execute(); + Response unitResponse = api.getUnits(subArrayForLoading).execute(); if (!unitResponse.isSuccessful()) { responseIsSuccess = false; } else { diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index f458003728..855b2fc565 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -31,22 +31,22 @@ enum TokenType { Call signUp(String firstName, String secondName, String email, String password); - Single getEnrolledCourses(int page); + Single getEnrolledCourses(int page); - Single getPopularCourses(int page); + Single getPopularCourses(int page); Call getUserProfile(); - Call getUsers(long[] userIds); + Call getUsers(long[] userIds); Call tryJoinCourse(@NotNull Course course); - Call getSections(long[] sectionsIds); + Call getSections(long[] sectionsIds); /** * Max number of units defined in AppConstants */ - Call getUnits(long[] units); + Call getUnits(long[] units); Call getLessons(long[] lessons); @@ -67,7 +67,7 @@ enum TokenType { Call getSearchResultsCourses(int page, String rawQuery); - Call getCourses(int page, long[] ids); + Call getCourses(int page, long[] ids); Call createNewAttempt(long stepId); @@ -89,7 +89,7 @@ enum TokenType { Call registerDevice(String token); - Call getCourse(long id); + Call getCourse(long id); Call setReadStatusForNotification(long notificationId, boolean isRead); @@ -111,7 +111,7 @@ enum TokenType { Call getCertificates(); - Call getUnitByLessonId(long lessonId); + Call getUnitByLessonId(long lessonId); Call getNotifications(NotificationCategory notificationCategory, int page); @@ -122,4 +122,6 @@ enum TokenType { Call getLastStepResponse(@NotNull String lastStepId); Call getCourseLists (); + + Single getCourseReviews (long[] courseIds); } diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 6a5da014c3..53b6881971 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -412,11 +412,11 @@ private String getCsrfTokenFromCookies(String cookies) { return csrftoken; } - public Single getEnrolledCourses(int page) { + public Single getEnrolledCourses(int page) { return loggedService.getEnrolledCourses(page); } - public Single getPopularCourses(int page) { + public Single getPopularCourses(int page) { return loggedService.getPopularCourses(page); } @@ -426,7 +426,7 @@ public Call getUserProfile() { } @Override - public Call getUsers(long[] userIds) { + public Call getUsers(long[] userIds) { return loggedService.getUsers(userIds); } @@ -438,12 +438,12 @@ public Call tryJoinCourse(@NotNull Course course) { } @Override - public Call getSections(long[] sectionsIds) { + public Call getSections(long[] sectionsIds) { return loggedService.getSections(sectionsIds); } @Override - public Call getUnits(long[] units) { + public Call getUnits(long[] units) { return loggedService.getUnits(units); } @@ -506,7 +506,7 @@ public Call getSearchResultsCourses(int page, String rawQu } @Override - public Call getCourses(int page, @Nullable long[] ids) { + public Call getCourses(int page, @Nullable long[] ids) { if (ids == null || ids.length == 0) { ids = new long[]{0}; } @@ -646,7 +646,7 @@ public Call registerDevice(String token) { } @Override - public Call getCourse(long id) { + public Call getCourse(long id) { long[] ids = new long[]{id}; return loggedService.getCourses(ids); } @@ -717,7 +717,7 @@ public Call getCertificates() { } @Override - public Call getUnitByLessonId(long lessonId) { + public Call getUnitByLessonId(long lessonId) { return loggedService.getUnitByLessonId(lessonId); } @@ -751,6 +751,11 @@ public Call getCourseLists() { } + @Override + public Single getCourseReviews(long[] courseIds) { + return loggedService.getCourseReviews(courseIds); + } + @Nullable private String getNotificationCategoryString(NotificationCategory notificationCategory) { String categoryType; diff --git a/app/src/main/java/org/stepic/droid/web/AssignmentResponse.java b/app/src/main/java/org/stepic/droid/web/AssignmentResponse.java index 27358bee6f..203ceeadc2 100644 --- a/app/src/main/java/org/stepic/droid/web/AssignmentResponse.java +++ b/app/src/main/java/org/stepic/droid/web/AssignmentResponse.java @@ -5,7 +5,7 @@ import java.util.List; -public class AssignmentResponse extends StepicResponseBase { +public class AssignmentResponse extends MetaResponseBase { private final List assignments; public AssignmentResponse(Meta meta, List assignmentList) { diff --git a/app/src/main/java/org/stepic/droid/web/CourseListsResponse.kt b/app/src/main/java/org/stepic/droid/web/CourseListsResponse.kt index 7c37da4f31..897caf89f3 100644 --- a/app/src/main/java/org/stepic/droid/web/CourseListsResponse.kt +++ b/app/src/main/java/org/stepic/droid/web/CourseListsResponse.kt @@ -8,4 +8,4 @@ class CourseListsResponse( meta: Meta, @SerializedName("course-lists") val courseLists: List -) : StepicResponseBase(meta) +) : MetaResponseBase(meta) diff --git a/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt b/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt new file mode 100644 index 0000000000..d509ca81bd --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt @@ -0,0 +1,8 @@ +package org.stepic.droid.web + +import org.stepic.droid.model.Meta + +class CourseReviewResponse( + meta: Meta, + val average: Double +) : MetaResponseBase(meta) diff --git a/app/src/main/java/org/stepic/droid/web/CoursesStepicResponse.java b/app/src/main/java/org/stepic/droid/web/CoursesMetaResponse.java similarity index 69% rename from app/src/main/java/org/stepic/droid/web/CoursesStepicResponse.java rename to app/src/main/java/org/stepic/droid/web/CoursesMetaResponse.java index 14ccb1d782..3b9bd2f8b6 100644 --- a/app/src/main/java/org/stepic/droid/web/CoursesStepicResponse.java +++ b/app/src/main/java/org/stepic/droid/web/CoursesMetaResponse.java @@ -5,10 +5,10 @@ import java.util.List; -public class CoursesStepicResponse extends StepicResponseBase { +public class CoursesMetaResponse extends MetaResponseBase { private List courses; - public CoursesStepicResponse(List courses, Meta meta) { + public CoursesMetaResponse(List courses, Meta meta) { super(meta); this.courses = courses; } diff --git a/app/src/main/java/org/stepic/droid/web/IStepicResponse.java b/app/src/main/java/org/stepic/droid/web/IStepicResponse.java deleted file mode 100644 index 2c9462c63d..0000000000 --- a/app/src/main/java/org/stepic/droid/web/IStepicResponse.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.stepic.droid.web; - -import java.io.Serializable; - -public interface IStepicResponse extends Serializable { -} diff --git a/app/src/main/java/org/stepic/droid/web/MetaResponseBase.kt b/app/src/main/java/org/stepic/droid/web/MetaResponseBase.kt new file mode 100644 index 0000000000..4ad5ee295d --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/MetaResponseBase.kt @@ -0,0 +1,5 @@ +package org.stepic.droid.web + +import org.stepic.droid.model.Meta + +abstract class MetaResponseBase(val meta: Meta) diff --git a/app/src/main/java/org/stepic/droid/web/NotificationResponse.java b/app/src/main/java/org/stepic/droid/web/NotificationResponse.java index b2239f0af7..db7d2f8e70 100644 --- a/app/src/main/java/org/stepic/droid/web/NotificationResponse.java +++ b/app/src/main/java/org/stepic/droid/web/NotificationResponse.java @@ -5,7 +5,7 @@ import java.util.List; -public class NotificationResponse extends StepicResponseBase { +public class NotificationResponse extends MetaResponseBase { List notifications; diff --git a/app/src/main/java/org/stepic/droid/web/ProgressesResponse.java b/app/src/main/java/org/stepic/droid/web/ProgressesResponse.java index 88b1b6a456..ae1c7f33f8 100644 --- a/app/src/main/java/org/stepic/droid/web/ProgressesResponse.java +++ b/app/src/main/java/org/stepic/droid/web/ProgressesResponse.java @@ -5,7 +5,7 @@ import java.util.List; -public class ProgressesResponse extends StepicResponseBase { +public class ProgressesResponse extends MetaResponseBase { List progresses; diff --git a/app/src/main/java/org/stepic/droid/web/SearchResultResponse.java b/app/src/main/java/org/stepic/droid/web/SearchResultResponse.java index 307421a0d6..9493809441 100644 --- a/app/src/main/java/org/stepic/droid/web/SearchResultResponse.java +++ b/app/src/main/java/org/stepic/droid/web/SearchResultResponse.java @@ -7,7 +7,7 @@ import java.util.List; -public class SearchResultResponse extends StepicResponseBase { +public class SearchResultResponse extends MetaResponseBase { @SerializedName("search-results") List searchResultList; diff --git a/app/src/main/java/org/stepic/droid/web/SectionsStepicResponse.java b/app/src/main/java/org/stepic/droid/web/SectionsMetaResponse.java similarity index 69% rename from app/src/main/java/org/stepic/droid/web/SectionsStepicResponse.java rename to app/src/main/java/org/stepic/droid/web/SectionsMetaResponse.java index 1b26854dd6..eeafe0e73a 100644 --- a/app/src/main/java/org/stepic/droid/web/SectionsStepicResponse.java +++ b/app/src/main/java/org/stepic/droid/web/SectionsMetaResponse.java @@ -5,11 +5,11 @@ import java.util.List; -public class SectionsStepicResponse extends StepicResponseBase { +public class SectionsMetaResponse extends MetaResponseBase { private List
sections; - public SectionsStepicResponse(List
sections, Meta meta) { + public SectionsMetaResponse(List
sections, Meta meta) { super(meta); this.sections = sections; } diff --git a/app/src/main/java/org/stepic/droid/web/SignUpResponse.java b/app/src/main/java/org/stepic/droid/web/SignUpResponse.java deleted file mode 100644 index 92723af32a..0000000000 --- a/app/src/main/java/org/stepic/droid/web/SignUpResponse.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.stepic.droid.web; - -public class SignUpResponse implements IStepicResponse { -} diff --git a/app/src/main/java/org/stepic/droid/web/StepResponse.kt b/app/src/main/java/org/stepic/droid/web/StepResponse.kt index f4b459d78c..f4cb80b2e3 100644 --- a/app/src/main/java/org/stepic/droid/web/StepResponse.kt +++ b/app/src/main/java/org/stepic/droid/web/StepResponse.kt @@ -3,5 +3,5 @@ package org.stepic.droid.web import org.stepic.droid.model.Meta import org.stepic.droid.model.Step -class StepResponse(meta: Meta, val steps: List?) : StepicResponseBase(meta) { +class StepResponse(meta: Meta, val steps: List?) : MetaResponseBase(meta) { } diff --git a/app/src/main/java/org/stepic/droid/web/StepicResponseBase.java b/app/src/main/java/org/stepic/droid/web/StepicResponseBase.java deleted file mode 100644 index 2e7db7aafb..0000000000 --- a/app/src/main/java/org/stepic/droid/web/StepicResponseBase.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.stepic.droid.web; - -import org.stepic.droid.model.Meta; - -public abstract class StepicResponseBase implements IStepicResponse { - - private Meta meta; - - public StepicResponseBase(Meta meta) { - this.meta = meta; - } - - public final Meta getMeta() { - return meta; - } -} diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index 220e4dcdab..e63c64486b 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -18,26 +18,26 @@ public interface StepicRestLoggedService { @GET("api/sections") - Call getSections(@Query("ids[]") long[] sectionIds); + Call getSections(@Query("ids[]") long[] sectionIds); @Headers({"Content-Type:application/json"}) @POST("api/enrollments") Call joinCourse(@Body EnrollmentWrapper enrollmentCourse); @GET("api/users") - Call getUsers(@Query("ids[]") long[] userIds); + Call getUsers(@Query("ids[]") long[] userIds); @GET("api/stepics/1") Call getUserProfile(); @GET("api/courses?enrolled=true") - Single getEnrolledCourses(@Query("page") int page); + Single getEnrolledCourses(@Query("page") int page); @GET("api/courses?is_public=true&order=-activity") - Single getPopularCourses(@Query("page") int page); + Single getPopularCourses(@Query("page") int page); @GET("api/units") - Call getUnits(@Query("ids[]") long[] units); + Call getUnits(@Query("ids[]") long[] units); @GET("api/lessons") Call getLessons(@Query("ids[]") long[] lessons); @@ -67,7 +67,7 @@ Call getSearchResults(@Query("page") int page, @Query(value = "query", encoded = true) String encodedQuery, @Query("type") String type); @GET("api/courses") - Call getCourses(@Query("page") int page, @Query("ids[]") long[] courseIds); + Call getCourses(@Query("page") int page, @Query("ids[]") long[] courseIds); @POST("api/attempts") Call createNewAttempt(@Body AttemptRequest attemptRequest); @@ -91,7 +91,7 @@ Call getSearchResults(@Query("page") int page, Call registerDevice(@Body DeviceRequest deviceRequest); @GET("api/courses") - Call getCourses(@Query("ids[]") long[] courseIds); + Call getCourses(@Query("ids[]") long[] courseIds); @PUT("api/notifications/{id}") Call putNotification(@Path("id") long notificationId, @Body NotificationRequest notificationRequest); @@ -118,7 +118,7 @@ Call getSearchResults(@Query("page") int page, Call getCertificates(@Query("user") long userId); @GET("api/units") - Call getUnitByLessonId(@Query("lesson") long lessonId); + Call getUnitByLessonId(@Query("lesson") long lessonId); @GET("api/steps") Call geStepsByLessonId(@Query("lesson") long lessonId); @@ -141,4 +141,7 @@ Call getSearchResults(@Query("page") int page, @GET("api/course-lists?platform=mobile") Call getCourseLists(@Query("language") String language); + + @GET("api/course-review-summaries") + Single getCourseReviews(@Query("ids[]") long[] courseIds); } diff --git a/app/src/main/java/org/stepic/droid/web/UnitStepicResponse.java b/app/src/main/java/org/stepic/droid/web/UnitMetaResponse.java similarity index 70% rename from app/src/main/java/org/stepic/droid/web/UnitStepicResponse.java rename to app/src/main/java/org/stepic/droid/web/UnitMetaResponse.java index ffcadc7f3f..b1829e69f1 100644 --- a/app/src/main/java/org/stepic/droid/web/UnitStepicResponse.java +++ b/app/src/main/java/org/stepic/droid/web/UnitMetaResponse.java @@ -5,10 +5,10 @@ import java.util.List; -public class UnitStepicResponse extends StepicResponseBase { +public class UnitMetaResponse extends MetaResponseBase { List units; - public UnitStepicResponse(Meta meta) { + public UnitMetaResponse(Meta meta) { super(meta); } diff --git a/app/src/main/java/org/stepic/droid/web/UserStepicResponse.java b/app/src/main/java/org/stepic/droid/web/UserStepicResponse.java deleted file mode 100644 index 6d5597ecc3..0000000000 --- a/app/src/main/java/org/stepic/droid/web/UserStepicResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.stepic.droid.web; - -import org.stepic.droid.model.Meta; -import org.stepic.droid.model.User; - -import java.util.List; - -public class UserStepicResponse implements IStepicResponse{ - Meta meta; - List users; - - public Meta getMeta() { - return meta; - } - - public List getUsers() { - return users; - } -} diff --git a/app/src/main/java/org/stepic/droid/web/UsersResponse.kt b/app/src/main/java/org/stepic/droid/web/UsersResponse.kt new file mode 100644 index 0000000000..69a9f02126 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/UsersResponse.kt @@ -0,0 +1,9 @@ +package org.stepic.droid.web + +import org.stepic.droid.model.Meta +import org.stepic.droid.model.User + +class UsersResponse( + meta: Meta, + val users: List? +) : MetaResponseBase(meta) diff --git a/app/src/test/java/org/stepic/droid/core/presenters/InstructorsPresenterTest.java b/app/src/test/java/org/stepic/droid/core/presenters/InstructorsPresenterTest.java index 938f9a7c80..b908256821 100644 --- a/app/src/test/java/org/stepic/droid/core/presenters/InstructorsPresenterTest.java +++ b/app/src/test/java/org/stepic/droid/core/presenters/InstructorsPresenterTest.java @@ -14,7 +14,7 @@ import org.stepic.droid.testUtils.generators.FakeCourseGenerator; import org.stepic.droid.testUtils.generators.FakeUserGenerator; import org.stepic.droid.web.Api; -import org.stepic.droid.web.UserStepicResponse; +import org.stepic.droid.web.UsersResponse; import java.io.IOException; import java.util.ArrayList; @@ -105,7 +105,7 @@ public void oneInstructor_instructorsLoaded() { List instructorList = new ArrayList<>(); instructorList.add(instructor); - UserStepicResponse responseMock = mock(UserStepicResponse.class); + UsersResponse responseMock = mock(UsersResponse.class); when(responseMock.getUsers()).thenReturn(instructorList); ResponseGeneratorKt.useMockInsteadCall(when(api.getUsers(any(long[].class))), responseMock); @@ -154,7 +154,7 @@ public void multiplyFetchingSameCourse_showCachedData() { List instructorList = new ArrayList<>(); instructorList.add(instructor); - UserStepicResponse responseMock = mock(UserStepicResponse.class); + UsersResponse responseMock = mock(UsersResponse.class); when(responseMock.getUsers()).thenReturn(instructorList); ResponseGeneratorKt.useMockInsteadCall(when(api.getUsers(any(long[].class))), responseMock); diff --git a/app/src/test/java/org/stepic/droid/core/presenters/ProfilePresenterTest.java b/app/src/test/java/org/stepic/droid/core/presenters/ProfilePresenterTest.java index 51587195b6..fac2d9b63b 100644 --- a/app/src/test/java/org/stepic/droid/core/presenters/ProfilePresenterTest.java +++ b/app/src/test/java/org/stepic/droid/core/presenters/ProfilePresenterTest.java @@ -21,7 +21,7 @@ import org.stepic.droid.util.ProfileExtensionKt; import org.stepic.droid.util.UserExtensionKt; import org.stepic.droid.web.Api; -import org.stepic.droid.web.UserStepicResponse; +import org.stepic.droid.web.UsersResponse; import java.io.IOException; import java.util.List; @@ -186,7 +186,7 @@ public void initProfile_storedCachingLocally_successNotRepeat() { public void initProfile_notMy_success() throws IOException { profilePresenter.attachView(profileView); - UserStepicResponse responseMock = mock(UserStepicResponse.class); + UsersResponse responseMock = mock(UsersResponse.class); List userListMock = (List) mock(List.class); ResponseGeneratorKt.useMockInsteadCall(when(api.getUsers(any(long[].class))), responseMock); diff --git a/app/src/test/java/org/stepic/droid/core/presenters/SearchCoursesPresenterTest.java b/app/src/test/java/org/stepic/droid/core/presenters/SearchCoursesPresenterTest.java index 4e550ff645..05a2e12463 100644 --- a/app/src/test/java/org/stepic/droid/core/presenters/SearchCoursesPresenterTest.java +++ b/app/src/test/java/org/stepic/droid/core/presenters/SearchCoursesPresenterTest.java @@ -19,7 +19,7 @@ import org.stepic.droid.util.resolvers.SearchResolver; import org.stepic.droid.util.resolvers.SearchResolverImpl; import org.stepic.droid.web.Api; -import org.stepic.droid.web.CoursesStepicResponse; +import org.stepic.droid.web.CoursesMetaResponse; import org.stepic.droid.web.SearchResultResponse; import java.io.IOException; @@ -92,7 +92,7 @@ public void downloadData_oneCourse_success() throws IOException { //mock calling api for getting course long[] courseIds = new long[1]; courseIds[0] = expectedSingleSearchResult.getCourse(); - CoursesStepicResponse coursesStepicResponse = mock(CoursesStepicResponse.class); + CoursesMetaResponse coursesStepicResponse = mock(CoursesMetaResponse.class); when(coursesStepicResponse.getMeta()).thenReturn(onePageMeta); List expectedCourses = new ArrayList<>(); Course expectedCourse = FakeCourseGenerator.INSTANCE.generate(expectedCourseId); From 7c4b49a255bdd7592b218519bc5437345f64f873 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Fri, 3 Nov 2017 17:23:40 +0300 Subject: [PATCH 020/140] clean up search view style --- app/src/main/res/values/styles.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 6c5bf1fc81..4eb5246eaf 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -38,6 +38,8 @@ @style/StepikTheme.EditTextStyle + + @style/SearchViewStyle + + From c29f4182c2285a64de2f8f1154bddcdfdf85d04a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 16:53:51 +0300 Subject: [PATCH 021/140] add rating to course, when it is fetched from api show rating in course items --- .../PersistentCourseListPresenter.kt | 21 +++++++++ .../java/org/stepic/droid/model/Course.java | 11 +++++ .../stepic/droid/model/CourseReviewSummary.kt | 5 ++- .../droid/model/CoursesCarouselColorType.kt | 6 ++- .../stepic/droid/storage/DatabaseHelper.java | 3 ++ .../stepic/droid/storage/dao/CourseDaoImpl.kt | 2 + ...DbStructureEnrolledAndFeaturedCourses.java | 1 + .../view_hoders/CourseItemViewHolder.kt | 20 +++++++-- .../droid/ui/custom/CircleProgressView.kt | 7 ++- .../main/java/org/stepic/droid/web/Api.java | 2 +- .../java/org/stepic/droid/web/ApiImpl.java | 2 +- .../stepic/droid/web/CourseReviewResponse.kt | 5 ++- .../droid/web/LessonStepicResponse.java | 19 -------- .../stepic/droid/web/LessonStepicResponse.kt | 9 ++++ .../droid/web/StepicRestLoggedService.java | 2 +- app/src/main/res/layout/new_course_item.xml | 44 ++++++++++++++++--- app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values/strings.xml | 2 + 18 files changed, 125 insertions(+), 37 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/web/LessonStepicResponse.java create mode 100644 app/src/main/java/org/stepic/droid/web/LessonStepicResponse.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt index 1c0a47ddbe..847d8c983c 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt @@ -8,6 +8,7 @@ import org.stepic.droid.core.FilterApplicator import org.stepic.droid.core.presenters.contracts.CoursesView import org.stepic.droid.di.course_list.CourseListScope import org.stepic.droid.model.Course +import org.stepic.droid.model.CourseReviewSummary import org.stepic.droid.model.Progress import org.stepic.droid.model.StepikFilter import org.stepic.droid.preferences.SharedPreferenceHelper @@ -131,6 +132,15 @@ class PersistentCourseListPresenter } } + val reviewSummaryIds = coursesFromInternet.map { it.reviewSummary }.toIntArray() + val reviews: List? = try { + api.getCourseReviews(reviewSummaryIds).blockingGet().courseReviewSummaries + } catch (exception: Exception) { + //ok show without new ratings + null + } + applyReviewToCourses(reviews, coursesFromInternet) + try { //this lock need for not saving enrolled courses to database after user click logout RWLocks.ClearEnrollmentsLock.writeLock().lock() @@ -277,6 +287,17 @@ class PersistentCourseListPresenter } } + private fun applyReviewToCourses(reviews: List?, coursesFromInternet: List) { + val courseMap = coursesFromInternet.associateBy { it.courseId } + reviews?.forEach { review -> + courseMap[review.course] + ?.let { + it.rating = review.average + } + } + } + + fun loadMore(courseType: Table, needFilter: Boolean) { downloadData(courseType, needFilter, isRefreshing = false, isLoadMore = true) } diff --git a/app/src/main/java/org/stepic/droid/model/Course.java b/app/src/main/java/org/stepic/droid/model/Course.java index ad0709630e..a1ec0847ad 100644 --- a/app/src/main/java/org/stepic/droid/model/Course.java +++ b/app/src/main/java/org/stepic/droid/model/Course.java @@ -66,6 +66,8 @@ public final class Course implements Parcelable { private long learnersCount; @Nullable private String progress; + @SerializedName("review_summary") + private int reviewSummary; private Progress progressObject; private double rating; @@ -82,6 +84,13 @@ public void setRating(double rating) { this.rating = rating; } + public int getReviewSummary() { + return reviewSummary; + } + + public void setReviewSummary(int reviewSummary) { + this.reviewSummary = reviewSummary; + } @Nullable public Progress getProgressObject() { @@ -364,6 +373,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(progress); dest.writeParcelable(progressObject, flags); dest.writeDouble(rating); + dest.writeInt(reviewSummary); } protected Course(Parcel in) { @@ -405,6 +415,7 @@ protected Course(Parcel in) { progress = in.readString(); progressObject = in.readParcelable(Progress.class.getClassLoader()); rating = in.readDouble(); + reviewSummary = in.readInt(); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt b/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt index 919cd12517..e9e2732a10 100644 --- a/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt +++ b/app/src/main/java/org/stepic/droid/model/CourseReviewSummary.kt @@ -1,3 +1,6 @@ package org.stepic.droid.model -data class CourseReviewSummary(val average: Double) +data class CourseReviewSummary( + val course: Long, + val average: Double +) diff --git a/app/src/main/java/org/stepic/droid/model/CoursesCarouselColorType.kt b/app/src/main/java/org/stepic/droid/model/CoursesCarouselColorType.kt index c5b3312db3..eae7de630f 100644 --- a/app/src/main/java/org/stepic/droid/model/CoursesCarouselColorType.kt +++ b/app/src/main/java/org/stepic/droid/model/CoursesCarouselColorType.kt @@ -19,13 +19,15 @@ enum class CoursesCarouselColorType( val viewAllColorRes: Int ) : Parcelable { - Light(R.color.new_accent_color, + Light( + R.color.new_accent_color, R.drawable.course_widget_continue_background, R.drawable.course_widget_join_background, R.color.transparent, R.color.view_all_course_list_color ), - Dark(R.color.white, + Dark( + R.color.white, R.drawable.course_widget_continue_dark_background, R.drawable.course_widget_join_background, R.color.new_accent_color, diff --git a/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java b/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java index a7df540a7f..bba08a3b89 100644 --- a/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java +++ b/app/src/main/java/org/stepic/droid/storage/DatabaseHelper.java @@ -253,6 +253,9 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { private void upgradeFrom28To29(SQLiteDatabase db) { alterColumn(db, DbStructureEnrolledAndFeaturedCourses.ENROLLED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, REAL_TYPE); alterColumn(db, DbStructureEnrolledAndFeaturedCourses.FEATURED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, REAL_TYPE); + + alterColumn(db, DbStructureEnrolledAndFeaturedCourses.ENROLLED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.REVIEW_SUMMARY, INT_TYPE); + alterColumn(db, DbStructureEnrolledAndFeaturedCourses.FEATURED_COURSES, DbStructureEnrolledAndFeaturedCourses.Column.REVIEW_SUMMARY, INT_TYPE); } private void upgradeFrom27To28(SQLiteDatabase db) { diff --git a/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt b/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt index 970901a024..c86daba830 100644 --- a/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt +++ b/app/src/main/java/org/stepic/droid/storage/dao/CourseDaoImpl.kt @@ -49,6 +49,7 @@ constructor( course.learnersCount = cursor.getLong(DbStructureEnrolledAndFeaturedCourses.Column.LEARNERS_COUNT) course.progress = cursor.getString(DbStructureEnrolledAndFeaturedCourses.Column.PROGRESS) course.rating = cursor.getDouble(DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING) + course.reviewSummary = cursor.getInt(DbStructureEnrolledAndFeaturedCourses.Column.REVIEW_SUMMARY) var isActive = true try { @@ -99,6 +100,7 @@ constructor( values.put(DbStructureEnrolledAndFeaturedCourses.Column.LEARNERS_COUNT, course.learnersCount) values.put(DbStructureEnrolledAndFeaturedCourses.Column.PROGRESS, course.progress) values.put(DbStructureEnrolledAndFeaturedCourses.Column.AVERAGE_RATING, course.rating) + values.put(DbStructureEnrolledAndFeaturedCourses.Column.REVIEW_SUMMARY, course.reviewSummary) val video = course.introVideo if (video != null) { diff --git a/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java b/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java index fc6adf3488..41d57681be 100644 --- a/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java +++ b/app/src/main/java/org/stepic/droid/storage/structure/DbStructureEnrolledAndFeaturedCourses.java @@ -43,5 +43,6 @@ public static final class Column { public static final String LEARNERS_COUNT = "learners_count"; public static final String PROGRESS = "progress"; public static final String AVERAGE_RATING = "average_rating"; + public static final String REVIEW_SUMMARY = "review_summary"; } } diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt index 385c2dc45f..c83c23d14d 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt @@ -74,6 +74,8 @@ class CourseItemViewHolder( private val courseWidgetInfo = view.courseWidgetInfo private val courseItemProgress = view.courseItemProgressView private val courseItemProgressTitle = view.courseItemProgressTitle + private val courseRatingImage = view.courseRatingImage + private val courseRatingText = view.courseRatingText init { @@ -127,6 +129,9 @@ class CourseItemViewHolder( learnersCountText.setTextColor(ColorUtil.getColorArgb(colorType.textColor, itemView.context)) learnersCountImage.setColorFilter(ColorUtil.getColorArgb(colorType.textColor, itemView.context)) courseWidgetButton.setTextColor(ColorUtil.getColorArgb(colorType.textColor, itemView.context)) + courseRatingText.setTextColor(ColorUtil.getColorArgb(colorType.textColor, itemView.context)) + courseRatingImage.setColorFilter(ColorUtil.getColorArgb(colorType.textColor, itemView.context)) + courseItemProgress.backgroundPaintColor = ColorUtil.getColorArgb(colorType.textColor, itemView.context) } private fun showMore(view: View, course: Course) { @@ -206,12 +211,13 @@ class CourseItemViewHolder( showJoinButton() } - changeProgressView(course) + bindProgressView(course) + bindRatingView(course) courseItemMore.changeVisibility(showMore) } - private fun changeProgressView(course: Course) { + private fun bindProgressView(course: Course) { val progressPercent: Int? = ProgressUtil.getProgressPercent(course.progressObject) val needShow: Boolean = if (progressPercent != null && progressPercent > 0) { @@ -219,7 +225,6 @@ class CourseItemViewHolder( // title and image should be equal courseItemProgress.progress = progressPercent / 100f courseItemProgressTitle.text = itemView - .context .resources .getString(R.string.percent_symbol, progressPercent) true @@ -230,6 +235,15 @@ class CourseItemViewHolder( courseItemProgressTitle.changeVisibility(needShow) } + private fun bindRatingView(course: Course) { + val needShow = course.rating > 0 + if (needShow) { + courseRatingText.text = String.format(Locale.ROOT, itemView.resources.getString(R.string.course_rating_value), course.rating) + } + courseRatingImage.changeVisibility(needShow) + courseRatingText.changeVisibility(needShow) + } + private fun isEnrolled(course: Course?): Boolean = course != null && course.enrollment != 0 diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt index 1b611ea8c2..0d31eea66e 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CircleProgressView.kt @@ -43,7 +43,12 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: //Colors (with defaults) @ColorInt - private var backgroundPaintColor = ColorUtil.getColorArgb(R.color.new_accent_color, context) + var backgroundPaintColor = ColorUtil.getColorArgb(R.color.new_accent_color, context) + set(value) { + field = value + setupPaint(backgroundPaint, field) + invalidate() + } @ColorInt private var foregroundPaintColor = ColorUtil.getColorArgb(R.color.stepic_brand_primary, context) diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index 855b2fc565..2f57a96446 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -123,5 +123,5 @@ enum TokenType { Call getCourseLists (); - Single getCourseReviews (long[] courseIds); + Single getCourseReviews (int[] reviewSummaryIds); } diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 53b6881971..aaad3f8a61 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -752,7 +752,7 @@ public Call getCourseLists() { } @Override - public Single getCourseReviews(long[] courseIds) { + public Single getCourseReviews(int[] courseIds) { return loggedService.getCourseReviews(courseIds); } diff --git a/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt b/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt index d509ca81bd..8e5553c4ed 100644 --- a/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt +++ b/app/src/main/java/org/stepic/droid/web/CourseReviewResponse.kt @@ -1,8 +1,11 @@ package org.stepic.droid.web +import com.google.gson.annotations.SerializedName +import org.stepic.droid.model.CourseReviewSummary import org.stepic.droid.model.Meta class CourseReviewResponse( meta: Meta, - val average: Double + @SerializedName("course-review-summaries") + val courseReviewSummaries: List ) : MetaResponseBase(meta) diff --git a/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.java b/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.java deleted file mode 100644 index edfec71ed9..0000000000 --- a/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.stepic.droid.web; - -import org.stepic.droid.model.Lesson; -import org.stepic.droid.model.Meta; - -import java.util.List; - -public class LessonStepicResponse implements IStepicResponse { - Meta meta; - List lessons; - - public Meta getMeta() { - return meta; - } - - public List getLessons() { - return lessons; - } -} diff --git a/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.kt b/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.kt new file mode 100644 index 0000000000..bc365fe88b --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/LessonStepicResponse.kt @@ -0,0 +1,9 @@ +package org.stepic.droid.web + +import org.stepic.droid.model.Lesson +import org.stepic.droid.model.Meta + +class LessonStepicResponse( + meta: Meta, + val lessons: List? = null +) : MetaResponseBase(meta) diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index e63c64486b..12715885cf 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -143,5 +143,5 @@ Call getSearchResults(@Query("page") int page, Call getCourseLists(@Query("language") String language); @GET("api/course-review-summaries") - Single getCourseReviews(@Query("ids[]") long[] courseIds); + Single getCourseReviews(@Query("ids[]") int[] reviewSummaryIds); } diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index 4376d31ef4..2fb5291c02 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -73,6 +73,8 @@ android:layout_alignBaseline="@+id/learnersCountText" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" + android:layout_marginEnd="2dp" + android:layout_marginRight="2dp" android:baselineAlignBottom="true" android:clickable="false" android:contentDescription="@string/learners_count" @@ -86,24 +88,52 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" - android:layout_marginLeft="2dp" - android:layout_marginStart="2dp" android:layout_toEndOf="@id/learnersCountImage" android:layout_toRightOf="@id/learnersCountImage" android:textSize="16sp" tools:ignore="MissingPrefix" tools:text="999K"/> + + + + + android:layout_marginLeft="7dp" + android:layout_marginStart="7dp" + android:layout_toEndOf="@id/courseRatingText" + android:layout_toRightOf="@id/courseRatingText" + app:progressBarStroke="@dimen/course_item_progress_bar_size"/> <b>Пример выходных данных %d:</b> Введите код здесь… Шаг еще не обработан. Нажмите, чтобы перезагрузить + Рейтинг курса %d курс diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dec98ca1ff..ab564b498f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -545,6 +545,8 @@ <b>Sample output %d:</b> Type code here… Step is not prepared yet. Tap to reload + Course rating + %.1f %d course From 09460c727c1e09a667bd96dddd681450651a4941 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 18:57:30 +0300 Subject: [PATCH 022/140] extract a common part of text views in course widget to style for avoiding code duplication --- .../{ic_learnes.png => ic_learners.png} | Bin .../{ic_learnes.png => ic_learners.png} | Bin .../{ic_learnes.png => ic_learners.png} | Bin .../{ic_learnes.png => ic_learners.png} | Bin .../{ic_learnes.png => ic_learners.png} | Bin app/src/main/res/layout/new_course_item.xml | 28 +++--------------- app/src/main/res/values-v17/styles.xml | 9 ++++++ app/src/main/res/values/dimens.xml | 2 ++ app/src/main/res/values/styles.xml | 10 +++++++ 9 files changed, 25 insertions(+), 24 deletions(-) rename app/src/main/res/drawable-hdpi/{ic_learnes.png => ic_learners.png} (100%) rename app/src/main/res/drawable-mdpi/{ic_learnes.png => ic_learners.png} (100%) rename app/src/main/res/drawable-xhdpi/{ic_learnes.png => ic_learners.png} (100%) rename app/src/main/res/drawable-xxhdpi/{ic_learnes.png => ic_learners.png} (100%) rename app/src/main/res/drawable-xxxhdpi/{ic_learnes.png => ic_learners.png} (100%) create mode 100644 app/src/main/res/values-v17/styles.xml diff --git a/app/src/main/res/drawable-hdpi/ic_learnes.png b/app/src/main/res/drawable-hdpi/ic_learners.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_learnes.png rename to app/src/main/res/drawable-hdpi/ic_learners.png diff --git a/app/src/main/res/drawable-mdpi/ic_learnes.png b/app/src/main/res/drawable-mdpi/ic_learners.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_learnes.png rename to app/src/main/res/drawable-mdpi/ic_learners.png diff --git a/app/src/main/res/drawable-xhdpi/ic_learnes.png b/app/src/main/res/drawable-xhdpi/ic_learners.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_learnes.png rename to app/src/main/res/drawable-xhdpi/ic_learners.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_learnes.png b/app/src/main/res/drawable-xxhdpi/ic_learners.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_learnes.png rename to app/src/main/res/drawable-xxhdpi/ic_learners.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_learnes.png b/app/src/main/res/drawable-xxxhdpi/ic_learners.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_learnes.png rename to app/src/main/res/drawable-xxxhdpi/ic_learners.png diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index 2fb5291c02..840e1b2a98 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -73,25 +73,18 @@ android:layout_alignBaseline="@+id/learnersCountText" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" - android:layout_marginEnd="2dp" - android:layout_marginRight="2dp" android:baselineAlignBottom="true" android:clickable="false" android:contentDescription="@string/learners_count" android:focusable="false" android:focusableInTouchMode="false" - android:src="@drawable/ic_learnes"/> + android:src="@drawable/ic_learners"/> diff --git a/app/src/main/res/values-v17/styles.xml b/app/src/main/res/values-v17/styles.xml new file mode 100644 index 0000000000..ccb550ec21 --- /dev/null +++ b/app/src/main/res/values-v17/styles.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 4cba6fe7a6..f9e443d359 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -118,6 +118,8 @@ 0dp 11dp 2dp + 16sp + 2dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 6c5bf1fc81..7468b35006 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -287,6 +287,16 @@ end + + From be712d4a3dcff2355048e91ed046a0111c09d655 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 19:04:50 +0300 Subject: [PATCH 023/140] extract properties of image views in course widget --- app/src/main/res/layout/new_course_item.xml | 16 ++-------------- app/src/main/res/values-v17/styles.xml | 1 + app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/styles.xml | 9 +++++++++ 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index 840e1b2a98..32a6842d30 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -68,16 +68,12 @@ diff --git a/app/src/main/res/values-v17/styles.xml b/app/src/main/res/values-v17/styles.xml index ccb550ec21..973010972a 100644 --- a/app/src/main/res/values-v17/styles.xml +++ b/app/src/main/res/values-v17/styles.xml @@ -5,5 +5,6 @@ \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f9e443d359..eb31515994 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -120,6 +120,7 @@ 2dp 16sp 2dp + 7dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7468b35006..7ce0bcc5a2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -292,11 +292,20 @@ + + From 4a265902bd6c84c58c664d056e7325eeb816d22a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Fri, 3 Nov 2017 19:22:06 +0300 Subject: [PATCH 024/140] fix bug, when learners can be hidden and all properties become hidden --- .../view_hoders/CourseItemViewHolder.kt | 17 ++++++++++------- app/src/main/res/layout/new_course_item.xml | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt index c83c23d14d..5685863a0d 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/view_hoders/CourseItemViewHolder.kt @@ -70,7 +70,7 @@ class CourseItemViewHolder( private val learnersCountImage = view.learnersCountImage private val learnersCountText = view.learnersCountText private val courseItemMore = view.courseItemMore - private val learnersCountContainer = view.learnersCountContainer + private val coursePropertiesContainer = view.coursePropertiesContainer private val courseWidgetInfo = view.courseWidgetInfo private val courseItemProgress = view.courseItemProgressView private val courseItemProgressTitle = view.courseItemProgressTitle @@ -200,8 +200,6 @@ class CourseItemViewHolder( if (needShowLearners) { learnersCountText.text = String.format(Locale.getDefault(), "%d", course.learnersCount) } - learnersCountContainer.changeVisibility(needShowLearners) - if (isEnrolled(course)) { courseWidgetInfo.setText(R.string.course_item_syllabus) @@ -211,13 +209,16 @@ class CourseItemViewHolder( showJoinButton() } - bindProgressView(course) - bindRatingView(course) + val needShowProgress = bindProgressView(course) + val needShowRating = bindRatingView(course) + + val showContainer = needShowLearners || needShowProgress || needShowRating + coursePropertiesContainer.changeVisibility(showContainer) courseItemMore.changeVisibility(showMore) } - private fun bindProgressView(course: Course) { + private fun bindProgressView(course: Course): Boolean { val progressPercent: Int? = ProgressUtil.getProgressPercent(course.progressObject) val needShow: Boolean = if (progressPercent != null && progressPercent > 0) { @@ -233,15 +234,17 @@ class CourseItemViewHolder( } courseItemProgress.changeVisibility(needShow) courseItemProgressTitle.changeVisibility(needShow) + return needShow } - private fun bindRatingView(course: Course) { + private fun bindRatingView(course: Course): Boolean { val needShow = course.rating > 0 if (needShow) { courseRatingText.text = String.format(Locale.ROOT, itemView.resources.getString(R.string.course_rating_value), course.rating) } courseRatingImage.changeVisibility(needShow) courseRatingText.changeVisibility(needShow) + return needShow } private fun isEnrolled(course: Course?): Boolean = diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index 32a6842d30..a8e9ee5a61 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -57,7 +57,7 @@ app:layout_constraintTop_toTopOf="parent"/> Date: Tue, 7 Nov 2017 13:46:21 +0300 Subject: [PATCH 025/140] create catalog fragment and adapter for future using --- .../droid/ui/activities/MainFeedActivity.kt | 4 +- .../droid/ui/adapters/CatalogAdapter.kt | 50 +++++++++++++++++++ .../droid/ui/fragments/CatalogFragment.kt | 34 +++++++++++++ .../main/res/layout/catalog_courses_item.xml | 5 ++ app/src/main/res/layout/fragment_catalog.xml | 27 ++++++++++ .../res/layout/fragment_courses_carousel.xml | 14 ++++++ 6 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt create mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt create mode 100644 app/src/main/res/layout/catalog_courses_item.xml create mode 100644 app/src/main/res/layout/fragment_catalog.xml diff --git a/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt b/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt index 4955295f8f..51dd1e0414 100644 --- a/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt +++ b/app/src/main/java/org/stepic/droid/ui/activities/MainFeedActivity.kt @@ -26,8 +26,8 @@ import org.stepic.droid.ui.activities.contracts.RootScreen import org.stepic.droid.ui.dialogs.LoadingProgressDialogFragment import org.stepic.droid.ui.dialogs.LogoutAreYouSureDialog import org.stepic.droid.ui.dialogs.NeedUpdatingDialog +import org.stepic.droid.ui.fragments.CatalogFragment import org.stepic.droid.ui.fragments.CertificatesFragment -import org.stepic.droid.ui.fragments.FindCoursesFragment import org.stepic.droid.ui.fragments.HomeFragment import org.stepic.droid.ui.fragments.ProfileFragment import org.stepic.droid.util.AppConstants @@ -256,7 +256,7 @@ class MainFeedActivity : BackToExitActivityWithSmartLockBase(), getNextFragmentOrNull(currentFragmentTag, HomeFragment::class.java.simpleName, HomeFragment.Companion::newInstance) } R.id.find_courses -> { - getNextFragmentOrNull(currentFragmentTag, FindCoursesFragment::class.java.simpleName, FindCoursesFragment::newInstance) + getNextFragmentOrNull(currentFragmentTag, CatalogFragment::class.java.simpleName, CatalogFragment.Companion::newInstance) } R.id.profile -> { getNextFragmentOrNull(currentFragmentTag, ProfileFragment::class.java.simpleName, ProfileFragment.Companion::newInstance) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt new file mode 100644 index 0000000000..63431b14bc --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt @@ -0,0 +1,50 @@ +package org.stepic.droid.ui.adapters + +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import org.stepic.droid.R +import org.stepic.droid.model.CourseListItem + +class CatalogAdapter( + private val courseListItems: List +) : RecyclerView.Adapter() { + + companion object { + private const val CAROUSEL_TYPE = 0 + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + return when (viewType) { + CAROUSEL_TYPE -> { + val view = layoutInflater.inflate(R.layout.fragment_catalog, parent, false) + CarouselViewHolder(view) + } + else -> throw IllegalStateException("CatalogAdapter viewType = $viewType is unsupported") + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (getItemViewType(position)) { + CAROUSEL_TYPE -> courseListItemBy(adapterPosition = position) + } + } + + private fun courseListItemBy(adapterPosition: Int) { + courseListItems[adapterPosition] + } + + override fun getItemCount(): Int = courseListItems.size + + override fun getItemViewType(position: Int): Int = CAROUSEL_TYPE + + private class CarouselViewHolder(view: View) : RecyclerView.ViewHolder(view) { + + fun bindData(courseListItem: CourseListItem) { + //bind data + } + + } +} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt new file mode 100644 index 0000000000..b0787bcb25 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -0,0 +1,34 @@ +package org.stepic.droid.ui.fragments + +import android.os.Bundle +import android.support.v7.widget.LinearLayoutManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_catalog.* +import org.stepic.droid.R +import org.stepic.droid.base.FragmentBase +import org.stepic.droid.ui.util.initCenteredToolbar + +class CatalogFragment : FragmentBase() { + + companion object { + fun newInstance(): FragmentBase = CatalogFragment() + } + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater?.inflate(R.layout.fragment_catalog, container, false) + + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + initCenteredToolbar(R.string.catalog_title, showHomeButton = false) + initMainRecycler() + } + + private fun initMainRecycler() { + catalogRecyclerView.layoutManager = LinearLayoutManager(context) + } + +} diff --git a/app/src/main/res/layout/catalog_courses_item.xml b/app/src/main/res/layout/catalog_courses_item.xml new file mode 100644 index 0000000000..6400631790 --- /dev/null +++ b/app/src/main/res/layout/catalog_courses_item.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_catalog.xml b/app/src/main/res/layout/fragment_catalog.xml new file mode 100644 index 0000000000..012618a57e --- /dev/null +++ b/app/src/main/res/layout/fragment_catalog.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_courses_carousel.xml b/app/src/main/res/layout/fragment_courses_carousel.xml index 20ee89241d..3047b86040 100644 --- a/app/src/main/res/layout/fragment_courses_carousel.xml +++ b/app/src/main/res/layout/fragment_courses_carousel.xml @@ -7,11 +7,25 @@ android:layout_height="wrap_content" android:paddingBottom="@dimen/guideline_standard_padding"> + + Date: Tue, 7 Nov 2017 16:59:59 +0300 Subject: [PATCH 026/140] save scrolling position in carousel --- .../base/CoursesDatabaseFragmentBase.java | 7 - .../org/stepic/droid/core/ComponentManager.kt | 3 - .../stepic/droid/core/ComponentManagerImpl.kt | 17 +- .../di/course_list/CourseListComponent.kt | 4 +- .../droid/ui/adapters/CoursesAdapter.java | 9 +- .../ui/fragments/CourseDetailFragment.java | 7 - .../ui/fragments/CourseListFragmentBase.java | 10 +- .../ui/fragments/CourseSearchFragment.java | 7 - ...uselFragment.kt => CoursesCarouselView.kt} | 158 +++++++++++++----- .../ui/fragments/FastContinueFragment.kt | 6 - .../stepic/droid/ui/fragments/HomeFragment.kt | 28 ++-- .../droid/ui/fragments/SectionsFragment.java | 8 - .../res/layout/fragment_courses_carousel.xml | 1 + app/src/main/res/layout/fragment_home.xml | 21 ++- 14 files changed, 162 insertions(+), 124 deletions(-) rename app/src/main/java/org/stepic/droid/ui/fragments/{CoursesCarouselFragment.kt => CoursesCarouselView.kt} (76%) diff --git a/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java b/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java index a4788b653c..8441f7ab86 100644 --- a/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java +++ b/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java @@ -67,13 +67,6 @@ protected void injectComponent() { .inject(this); } - @Override - protected void onReleaseComponent() { - App.Companion - .componentManager() - .releaseCourseGeneralComponent(); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/stepic/droid/core/ComponentManager.kt b/app/src/main/java/org/stepic/droid/core/ComponentManager.kt index 2ff1fda440..f779111a6c 100644 --- a/app/src/main/java/org/stepic/droid/core/ComponentManager.kt +++ b/app/src/main/java/org/stepic/droid/core/ComponentManager.kt @@ -28,9 +28,6 @@ interface ComponentManager { @MainThread fun courseGeneralComponent(): CourseGeneralComponent - @MainThread - fun releaseCourseGeneralComponent() - @MainThread fun downloadsComponent(): DownloadsComponent diff --git a/app/src/main/java/org/stepic/droid/core/ComponentManagerImpl.kt b/app/src/main/java/org/stepic/droid/core/ComponentManagerImpl.kt index 760a59c2d3..de493d25af 100644 --- a/app/src/main/java/org/stepic/droid/core/ComponentManagerImpl.kt +++ b/app/src/main/java/org/stepic/droid/core/ComponentManagerImpl.kt @@ -109,20 +109,13 @@ class ComponentManagerImpl(private val appCoreComponent: AppCoreComponent) : Com // Course general - private val courseGeneralComponentHolder = ComponentHolder() - - override fun courseGeneralComponent(): CourseGeneralComponent { - return courseGeneralComponentHolder.get { - appCoreComponent - .courseGeneralComponentBuilder() - .build() - } - } - - override fun releaseCourseGeneralComponent() { - courseGeneralComponentHolder.release() + private val _courseGeneralComponent by lazy { + appCoreComponent + .courseGeneralComponentBuilder() + .build() } + override fun courseGeneralComponent(): CourseGeneralComponent = _courseGeneralComponent } class ComponentHolder { diff --git a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt index 691658fc67..e9368c5a64 100644 --- a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt @@ -4,7 +4,7 @@ import dagger.Subcomponent import org.stepic.droid.base.CoursesDatabaseFragmentBase import org.stepic.droid.ui.fragments.CourseListFragmentBase import org.stepic.droid.ui.fragments.CourseSearchFragment -import org.stepic.droid.ui.fragments.CoursesCarouselFragment +import org.stepic.droid.ui.fragments.CoursesCarouselView import org.stepic.droid.ui.fragments.FastContinueFragment @CourseListScope @@ -23,7 +23,7 @@ interface CourseListComponent { fun inject(fragment: CourseSearchFragment) - fun inject(fragment: CoursesCarouselFragment) + fun inject(view: CoursesCarouselView) fun inject(fragment: FastContinueFragment) } diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CoursesAdapter.java b/app/src/main/java/org/stepic/droid/ui/adapters/CoursesAdapter.java index ada5a0a410..794eafcad5 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CoursesAdapter.java +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CoursesAdapter.java @@ -1,11 +1,10 @@ package org.stepic.droid.ui.adapters; -import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; -import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import android.support.v4.graphics.drawable.RoundedBitmapDrawable; import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; import android.support.v7.widget.RecyclerView; @@ -56,7 +55,7 @@ public class CoursesAdapter extends RecyclerView.Adapter { private LayoutInflater inflater; - private Activity contextActivity; + private FragmentActivity contextActivity; private final List courses; private final ContinueCoursePresenter continueCoursePresenter; @NotNull @@ -72,7 +71,7 @@ public class CoursesAdapter extends RecyclerView.Adapter { private final boolean showMore; private final CoursesCarouselColorType colorType; - public CoursesAdapter(Fragment fragment, + public CoursesAdapter(FragmentActivity activity, List courses, @NotNull ContinueCoursePresenter continueCoursePresenter, @NotNull DroppingPresenter droppingPresenter, @@ -87,7 +86,7 @@ public CoursesAdapter(Fragment fragment, } else { NUMBER_OF_EXTRA_ITEMS = 0; } - contextActivity = fragment.getActivity(); + contextActivity = activity; this.courses = courses; this.continueCoursePresenter = continueCoursePresenter; this.droppingPresenter = droppingPresenter; diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseDetailFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/CourseDetailFragment.java index d0d3000e4b..8a4fad234f 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CourseDetailFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseDetailFragment.java @@ -195,13 +195,6 @@ protected void injectComponent() { .inject(this); } - @Override - protected void onReleaseComponent() { - App.Companion - .componentManager() - .releaseCourseGeneralComponent(); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java b/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java index dee9f6d030..9589180b7d 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java @@ -116,14 +116,6 @@ protected void injectComponent() { .inject(this); } - @Override - protected void onReleaseComponent() { - App - .Companion - .componentManager() - .releaseCourseGeneralComponent(); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -146,7 +138,7 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { if (courses == null) courses = new ArrayList<>(); boolean showMore = getCourseType() == Table.enrolled; - coursesAdapter = new CoursesAdapter(this, courses, continueCoursePresenter, droppingPresenter, true, showMore, CoursesCarouselColorType.Light); + coursesAdapter = new CoursesAdapter(getActivity(), courses, continueCoursePresenter, droppingPresenter, true, showMore, CoursesCarouselColorType.Light); listOfCoursesView.setAdapter(coursesAdapter); layoutManager = new WrapContentLinearLayoutManager(getContext()); listOfCoursesView.setLayoutManager(layoutManager); diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java index dd67ae5342..4c40a719cd 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java @@ -41,13 +41,6 @@ protected void injectComponent() { .inject(this); } - @Override - protected void onReleaseComponent() { - App.Companion - .componentManager() - .releaseCourseGeneralComponent(); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt similarity index 76% rename from app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselFragment.kt rename to app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt index f0c1b7448e..f74056d8e5 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt @@ -1,18 +1,22 @@ package org.stepic.droid.ui.fragments -import android.os.Bundle +import android.content.Context +import android.os.Parcel +import android.os.Parcelable import android.support.annotation.StringRes +import android.support.v4.app.FragmentActivity import android.support.v7.widget.GridLayoutManager +import android.util.AttributeSet import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup +import android.widget.FrameLayout import android.widget.Toast -import kotlinx.android.synthetic.main.fragment_courses_carousel.* +import kotlinx.android.synthetic.main.fragment_courses_carousel.view.* import org.stepic.droid.R import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App import org.stepic.droid.base.Client -import org.stepic.droid.base.FragmentBase +import org.stepic.droid.core.ScreenManager import org.stepic.droid.core.dropping.contract.DroppingListener import org.stepic.droid.core.joining.contract.JoiningListener import org.stepic.droid.core.presenters.ContinueCoursePresenter @@ -35,28 +39,26 @@ import org.stepic.droid.util.ColorUtil import org.stepic.droid.util.ProgressHelper import org.stepic.droid.util.StepikUtil import org.stepic.droid.util.SuppressFBWarnings +import timber.log.Timber import javax.inject.Inject @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "Kotlin adds null check for lateinit properties, but Findbugs highlights it as redundant") -class CoursesCarouselFragment - : FragmentBase(), +class CoursesCarouselView +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), ContinueCourseView, CoursesView, DroppingView, JoiningListener, DroppingListener { - companion object { - private const val COURSE_CAROUSEL_INFO_KEY = "COURSE_CAROUSEL_INFO_KEY" - - fun newInstance(coursesCarouselInfo: CoursesCarouselInfo): CoursesCarouselFragment { - val args = Bundle() - val fragment = CoursesCarouselFragment() - args.putParcelable(COURSE_CAROUSEL_INFO_KEY, coursesCarouselInfo) - fragment.arguments = args - return fragment - } - //FIXME: 04.09.17 if adapter.count < ROW_COUNT -> recycler creates extra padding + companion object { + private const val DEFAULT_SCROLL_POSITION = -1 private const val ROW_COUNT = 2 private const val continueLoadingTag = "continueLoadingTag" @@ -77,60 +79,76 @@ class CoursesCarouselFragment @Inject lateinit var joiningListenerClient: Client + @Inject + lateinit var screenManager: ScreenManager + + @Inject + lateinit var analytic: Analytic + private val courses = ArrayList() - private lateinit var info: CoursesCarouselInfo + + private var lastSavedScrollPosition: Int = DEFAULT_SCROLL_POSITION + + private var _info: CoursesCarouselInfo? = null + private set(value) { + field = value + if (field != null) { + onInfoInitialized() + } + } + private val info: CoursesCarouselInfo + get() = _info ?: throw IllegalStateException("Info is not set") + + private var gridLayoutManager: GridLayoutManager? = null + private val activity = context as FragmentActivity + private val fragmentManager = activity.supportFragmentManager - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - info = arguments.getParcelable(COURSE_CAROUSEL_INFO_KEY) + fun setCourseCarouselInfo(outerInfo: CoursesCarouselInfo) { + _info = outerInfo } - override fun injectComponent() { + init { App .componentManager() .courseGeneralComponent() .courseListComponentBuilder() .build() .inject(this) + + val layoutInflater = LayoutInflater.from(context) + layoutInflater.inflate(R.layout.fragment_courses_carousel, this, true) + Timber.d("this is created") } - override fun onReleaseComponent() { - App - .componentManager() - .releaseCourseGeneralComponent() + private fun onInfoInitialized() { + initCourseCarousel() + + courses.clear() + downloadData() + + restoreState() } - override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? - = inflater?.inflate(R.layout.fragment_courses_carousel, container, false) + override fun onAttachedToWindow() { + super.onAttachedToWindow() - override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initCourseCarousel() continueCoursePresenter.attachView(this) courseListPresenter.attachView(this) droppingPresenter.attachView(this) droppingClient.subscribe(this) joiningListenerClient.subscribe(this) - - restoreState() - - courses.clear() - downloadData() } - override fun onPause() { - super.onPause() - ProgressHelper.dismiss(fragmentManager, continueLoadingTag) - } + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() - override fun onDestroyView() { - super.onDestroyView() joiningListenerClient.unsubscribe(this) droppingClient.unsubscribe(this) continueCoursePresenter.detachView(this) courseListPresenter.detachView(this) droppingPresenter.detachView(this) + ProgressHelper.dismiss(fragmentManager, continueLoadingTag) } private fun initCourseCarousel() { @@ -147,7 +165,7 @@ class CoursesCarouselFragment gridLayoutManager = GridLayoutManager(context, ROW_COUNT, GridLayoutManager.HORIZONTAL, false) coursesRecycler.layoutManager = gridLayoutManager val showMore = info.table == Table.enrolled - coursesRecycler.adapter = CoursesAdapter(this, courses, continueCoursePresenter, droppingPresenter, false, showMore, info.colorType) + coursesRecycler.adapter = CoursesAdapter(context as FragmentActivity, courses, continueCoursePresenter, droppingPresenter, false, showMore, info.colorType) val verticalSpaceBetweenItems = resources.getDimensionPixelSize(R.dimen.course_list_between_items_padding) val leftSpacePx = resources.getDimensionPixelSize(R.dimen.course_list_side_padding) coursesRecycler.addItemDecoration(VerticalSpacesInGridDecoration(verticalSpaceBetweenItems / 2, ROW_COUNT)) //warning: verticalSpaceBetweenItems/2 – workaround for some bug, decoration will set this param twice @@ -227,6 +245,10 @@ class CoursesCarouselFragment override fun showCourses(courses: MutableList) { coursesLoadingView.visibility = View.GONE coursesPlaceholder.visibility = View.GONE + if (lastSavedScrollPosition != DEFAULT_SCROLL_POSITION) { + coursesRecycler.scrollToPosition(lastSavedScrollPosition) + lastSavedScrollPosition = DEFAULT_SCROLL_POSITION + } coursesRecycler.visibility = View.VISIBLE coursesViewAll.visibility = View.VISIBLE this.courses.clear() @@ -351,5 +373,55 @@ class CoursesCarouselFragment } } + public override fun onSaveInstanceState(): Parcelable { + val superState = super.onSaveInstanceState() + val savedState = SavedState(superState) + + savedState.info = this._info + savedState.scrollPosition = (coursesRecycler.layoutManager as GridLayoutManager).findFirstCompletelyVisibleItemPosition() + Timber.d("onSave ${savedState.scrollPosition}") + return savedState + } + + public override fun onRestoreInstanceState(state: Parcelable) { + if (state !is SavedState) { + super.onRestoreInstanceState(state) + return + } + + super.onRestoreInstanceState(state.superState) + + this._info = state.info + + lastSavedScrollPosition = state.scrollPosition + } + + private class SavedState : View.BaseSavedState { + + var info: CoursesCarouselInfo? = null + var scrollPosition: Int = 0 + + constructor(superState: Parcelable) : super(superState) + + private constructor(input: Parcel) : super(input) { + this.info = input.readParcelable(CoursesCarouselInfo::class.java.classLoader) + } + + override fun writeToParcel(out: Parcel, flags: Int) { + super.writeToParcel(out, flags) + out.writeParcelable(this.info, flags) + } + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(input: Parcel): SavedState = SavedState(input) + + override fun newArray(size: Int): Array = arrayOfNulls(size) + } + + } + } + } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt index f53310139c..755829be6f 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt @@ -79,12 +79,6 @@ class FastContinueFragment : FragmentBase(), .inject(this) } - override fun onReleaseComponent() { - App - .componentManager() - .releaseCourseGeneralComponent() - } - override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater?.inflate(R.layout.fragment_fast_continue, container, false) diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/HomeFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/HomeFragment.kt index e4d0937a79..45f075836b 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/HomeFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/HomeFragment.kt @@ -1,9 +1,11 @@ package org.stepic.droid.ui.fragments +import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_home.* import org.stepic.droid.R import org.stepic.droid.base.FragmentBase import org.stepic.droid.model.CoursesCarouselColorType @@ -14,40 +16,40 @@ import org.stepic.droid.ui.util.initCenteredToolbar class HomeFragment : FragmentBase() { companion object { fun newInstance(): HomeFragment = HomeFragment() - private const val myCoursesTag = "my_courses" - private const val popularCoursesTag = "popular_courses" private const val fastContinueTag = "fastContinueTag" } override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater?.inflate(R.layout.fragment_home, container, false) + @SuppressLint("CommitTransaction") override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { nullifyActivityBackground() super.onViewCreated(view, savedInstanceState) initCenteredToolbar(R.string.home_title) if (savedInstanceState == null) { - val fragmentTransaction = childFragmentManager.beginTransaction() + childFragmentManager + .beginTransaction() //false positive Lint: ... should completed with commit() + .add(R.id.homeFastContinueContainer, FastContinueFragment.newInstance(), fastContinueTag) + .commitNow() - val fastContinueFragment = FastContinueFragment.newInstance() - fragmentTransaction.add(R.id.homeFragmentsContainer, fastContinueFragment, fastContinueTag) - val myCoursesFragment = CoursesCarouselFragment.newInstance(CoursesCarouselInfo( + myCoursesView.setCourseCarouselInfo(CoursesCarouselInfo( CoursesCarouselColorType.Light, getString(R.string.my_courses_title), Table.enrolled, - null)) - fragmentTransaction.add(R.id.homeFragmentsContainer, myCoursesFragment, myCoursesTag) + null) + ) - val popularCoursesFragment = CoursesCarouselFragment.newInstance(CoursesCarouselInfo( + popularCoursesView.setCourseCarouselInfo(CoursesCarouselInfo( CoursesCarouselColorType.Dark, getString(R.string.popular_courses_title), Table.featured, - null - )) - fragmentTransaction.add(R.id.homeFragmentsContainer, popularCoursesFragment, popularCoursesTag) - fragmentTransaction.commit() + null) + ) } + + } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/SectionsFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/SectionsFragment.java index b09f6fba8f..10932de63c 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/SectionsFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/SectionsFragment.java @@ -223,14 +223,6 @@ protected void injectComponent() { .inject(this); } - @Override - protected void onReleaseComponent() { - App - .Companion - .componentManager() - .releaseCourseGeneralComponent(); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/res/layout/fragment_courses_carousel.xml b/app/src/main/res/layout/fragment_courses_carousel.xml index 3047b86040..c939a7ff49 100644 --- a/app/src/main/res/layout/fragment_courses_carousel.xml +++ b/app/src/main/res/layout/fragment_courses_carousel.xml @@ -95,6 +95,7 @@ android:scrollbarStyle="outsideOverlay" android:scrollbars="none" android:splitMotionEvents="false" + android:visibility="gone" /> + android:orientation="vertical"> + + + + + + + + \ No newline at end of file From 7f28f3c6f764d84ff8a91644c58f2f102e201d8e Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Tue, 7 Nov 2017 17:47:01 +0300 Subject: [PATCH 027/140] move courseListView from fragments to custom --- .../org/stepic/droid/di/course_list/CourseListComponent.kt | 2 +- .../droid/ui/{fragments => custom}/CoursesCarouselView.kt | 2 +- app/src/main/res/layout/catalog_item.xml | 5 +++++ app/src/main/res/layout/fragment_home.xml | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) rename app/src/main/java/org/stepic/droid/ui/{fragments => custom}/CoursesCarouselView.kt (99%) create mode 100644 app/src/main/res/layout/catalog_item.xml diff --git a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt index e9368c5a64..162d88883e 100644 --- a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt @@ -4,7 +4,7 @@ import dagger.Subcomponent import org.stepic.droid.base.CoursesDatabaseFragmentBase import org.stepic.droid.ui.fragments.CourseListFragmentBase import org.stepic.droid.ui.fragments.CourseSearchFragment -import org.stepic.droid.ui.fragments.CoursesCarouselView +import org.stepic.droid.ui.custom.CoursesCarouselView import org.stepic.droid.ui.fragments.FastContinueFragment @CourseListScope diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt similarity index 99% rename from app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt rename to app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index f74056d8e5..d04fe6c58c 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -1,4 +1,4 @@ -package org.stepic.droid.ui.fragments +package org.stepic.droid.ui.custom import android.content.Context import android.os.Parcel diff --git a/app/src/main/res/layout/catalog_item.xml b/app/src/main/res/layout/catalog_item.xml new file mode 100644 index 0000000000..fc5af7a868 --- /dev/null +++ b/app/src/main/res/layout/catalog_item.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 2dd8965fec..258b60498c 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -28,12 +28,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content"/> - - From 6746fead001927aec7bee31a9a5b3323293ca922 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Tue, 7 Nov 2017 19:05:11 +0300 Subject: [PATCH 028/140] change behaviour of carousels, fix presenting. (popular+my courses in catalog list for feature presenting) --- .../PersistentCourseListPresenter.kt | 8 +-- .../droid/ui/adapters/CatalogAdapter.kt | 43 +++++++++++++--- .../droid/ui/custom/CoursesCarouselView.kt | 51 ++++++++++++------- .../droid/ui/fragments/CatalogFragment.kt | 3 ++ app/src/main/res/layout/catalog_item.xml | 1 + .../res/layout/fragment_courses_carousel.xml | 2 +- 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt index 2a4cd7ad5b..b7c01f38f6 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt @@ -16,7 +16,6 @@ import org.stepic.droid.storage.operations.Table import org.stepic.droid.util.RWLocks import org.stepic.droid.web.Api import org.stepic.droid.web.CoursesStepicResponse -import timber.log.Timber import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger import javax.inject.Inject @@ -65,15 +64,10 @@ class PersistentCourseListPresenter return } currentNumberOfTasks++ - Timber.d("load more tasks = $currentNumberOfTasks") //here 1 or 2, not more - if (hasNextPage.get()) { - view?.showLoading() - } + view?.showLoading() singleThreadExecutor.execute { try { - Timber.d("load more start downloading ${Thread.currentThread()}") downloadDataPlain(isRefreshing, isLoadMore, applyFilter, courseType) - Timber.d("load more end downloading ${Thread.currentThread()}") } finally { mainHandler.post { currentNumberOfTasks-- diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt index 63431b14bc..6f88013945 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt @@ -4,8 +4,12 @@ import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import kotlinx.android.synthetic.main.catalog_item.view.* import org.stepic.droid.R import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselColorType +import org.stepic.droid.model.CoursesCarouselInfo +import org.stepic.droid.storage.operations.Table class CatalogAdapter( private val courseListItems: List @@ -19,7 +23,7 @@ class CatalogAdapter( val layoutInflater = LayoutInflater.from(parent.context) return when (viewType) { CAROUSEL_TYPE -> { - val view = layoutInflater.inflate(R.layout.fragment_catalog, parent, false) + val view = layoutInflater.inflate(R.layout.catalog_item, parent, false) CarouselViewHolder(view) } else -> throw IllegalStateException("CatalogAdapter viewType = $viewType is unsupported") @@ -27,23 +31,48 @@ class CatalogAdapter( } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (getItemViewType(position)) { - CAROUSEL_TYPE -> courseListItemBy(adapterPosition = position) - } + (holder as CarouselViewHolder).bindData(position) +// +// when (getItemViewType(position)) { +// CAROUSEL_TYPE -> (holder as CarouselViewHolder).bindData(courseListItemBy(adapterPosition = position)) +// } } private fun courseListItemBy(adapterPosition: Int) { courseListItems[adapterPosition] } - override fun getItemCount(): Int = courseListItems.size + override fun getItemCount(): Int = 10 override fun getItemViewType(position: Int): Int = CAROUSEL_TYPE private class CarouselViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bindData(courseListItem: CourseListItem) { - //bind data + private val coursesCarousel = itemView.coursesCarouselItem + + fun bindData(position: Int) { + val my = CoursesCarouselInfo( + CoursesCarouselColorType.Light, + itemView.resources.getString(R.string.my_courses_title), + Table.enrolled, + null) + + val popular = CoursesCarouselInfo( + CoursesCarouselColorType.Dark, + itemView.resources.getString(R.string.popular_courses_title), + Table.featured, + null) + + val info = + if (position % 2 == 0) { + my + } else { + popular + } + + coursesCarousel.setCourseCarouselInfo(info) + + } } diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index d04fe6c58c..24be22b6f4 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -5,6 +5,7 @@ import android.os.Parcel import android.os.Parcelable import android.support.annotation.StringRes import android.support.v4.app.FragmentActivity +import android.support.v4.view.ViewCompat import android.support.v7.widget.GridLayoutManager import android.util.AttributeSet import android.view.LayoutInflater @@ -92,12 +93,13 @@ constructor( private var _info: CoursesCarouselInfo? = null private set(value) { field = value - if (field != null) { - onInfoInitialized() + if (value != null) { + onInfoInitialized(value) } } private val info: CoursesCarouselInfo get() = _info ?: throw IllegalStateException("Info is not set") + private var needExecuteOnInfoInitialized = false private var gridLayoutManager: GridLayoutManager? = null @@ -118,16 +120,22 @@ constructor( val layoutInflater = LayoutInflater.from(context) layoutInflater.inflate(R.layout.fragment_courses_carousel, this, true) - Timber.d("this is created") + initCourseCarousel() } - private fun onInfoInitialized() { - initCourseCarousel() + private fun onInfoInitialized(info: CoursesCarouselInfo) { + needExecuteOnInfoInitialized = if (ViewCompat.isAttachedToWindow(this)) { + initCourseCarouselWithInfo(info) + + courses.clear() + downloadData() - courses.clear() - downloadData() + restoreState() - restoreState() + false + } else { + true + } } override fun onAttachedToWindow() { @@ -138,6 +146,10 @@ constructor( droppingPresenter.attachView(this) droppingClient.subscribe(this) joiningListenerClient.subscribe(this) + + if (needExecuteOnInfoInitialized) { + onInfoInitialized(info) + } } override fun onDetachedFromWindow() { @@ -152,22 +164,16 @@ constructor( } private fun initCourseCarousel() { - coursesCarouselTitle.text = getCarouselTitle() - coursesCarouselTitle.setTextColor(ColorUtil.getColorArgb(info.colorType.textColor)) - - coursesCarouselRoot.setBackgroundColor(ColorUtil.getColorArgb(info.colorType.backgroundColorRes)) - + coursesCarouselCount.visibility = View.GONE coursesViewAll.setOnClickListener { viewAll() } - coursesViewAll.setTextColor(ColorUtil.getColorArgb(info.colorType.viewAllColorRes, context)) gridLayoutManager = GridLayoutManager(context, ROW_COUNT, GridLayoutManager.HORIZONTAL, false) coursesRecycler.layoutManager = gridLayoutManager - val showMore = info.table == Table.enrolled - coursesRecycler.adapter = CoursesAdapter(context as FragmentActivity, courses, continueCoursePresenter, droppingPresenter, false, showMore, info.colorType) val verticalSpaceBetweenItems = resources.getDimensionPixelSize(R.dimen.course_list_between_items_padding) val leftSpacePx = resources.getDimensionPixelSize(R.dimen.course_list_side_padding) + coursesRecycler.addItemDecoration(VerticalSpacesInGridDecoration(verticalSpaceBetweenItems / 2, ROW_COUNT)) //warning: verticalSpaceBetweenItems/2 – workaround for some bug, decoration will set this param twice coursesRecycler.addItemDecoration(LeftSpacesDecoration(leftSpacePx)) coursesRecycler.addItemDecoration(RightMarginForLastItems(resources.getDimensionPixelSize(R.dimen.home_right_recycler_padding_without_extra), ROW_COUNT)) @@ -176,6 +182,16 @@ constructor( snapHelper.attachToRecyclerView(coursesRecycler) } + private fun initCourseCarouselWithInfo(info: CoursesCarouselInfo) { + coursesCarouselTitle.text = getCarouselTitle(info) + coursesCarouselTitle.setTextColor(ColorUtil.getColorArgb(info.colorType.textColor)) + coursesCarouselRoot.setBackgroundColor(ColorUtil.getColorArgb(info.colorType.backgroundColorRes)) + coursesViewAll.setTextColor(ColorUtil.getColorArgb(info.colorType.viewAllColorRes, context)) + + val showMore = info.table == Table.enrolled + coursesRecycler.adapter = CoursesAdapter(context as FragmentActivity, courses, continueCoursePresenter, droppingPresenter, false, showMore, info.colorType) + } + override fun onOpenStep(courseId: Long, section: Section, lessonId: Long, unitId: Long, stepPosition: Int) { ProgressHelper.dismiss(fragmentManager, continueLoadingTag) screenManager.continueCourse(activity, courseId, section, lessonId, unitId, stepPosition.toLong()) @@ -194,6 +210,7 @@ constructor( } override fun showLoading() { + Timber.d("show loading") coursesViewAll.visibility = View.GONE coursesRecycler.visibility = View.GONE coursesPlaceholder.visibility = View.GONE @@ -307,7 +324,7 @@ constructor( } - private fun getCarouselTitle(): String = info.title + private fun getCarouselTitle(info: CoursesCarouselInfo): String = info.title private fun restoreState() { if (info.table != null) { diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt index b0787bcb25..1c42a7b07c 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -8,6 +8,8 @@ import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_catalog.* import org.stepic.droid.R import org.stepic.droid.base.FragmentBase +import org.stepic.droid.model.CourseListItem +import org.stepic.droid.ui.adapters.CatalogAdapter import org.stepic.droid.ui.util.initCenteredToolbar class CatalogFragment : FragmentBase() { @@ -29,6 +31,7 @@ class CatalogFragment : FragmentBase() { private fun initMainRecycler() { catalogRecyclerView.layoutManager = LinearLayoutManager(context) + catalogRecyclerView.adapter = CatalogAdapter(emptyList()) } } diff --git a/app/src/main/res/layout/catalog_item.xml b/app/src/main/res/layout/catalog_item.xml index fc5af7a868..11d9257204 100644 --- a/app/src/main/res/layout/catalog_item.xml +++ b/app/src/main/res/layout/catalog_item.xml @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_courses_carousel.xml b/app/src/main/res/layout/fragment_courses_carousel.xml index c939a7ff49..7146c949ce 100644 --- a/app/src/main/res/layout/fragment_courses_carousel.xml +++ b/app/src/main/res/layout/fragment_courses_carousel.xml @@ -53,7 +53,7 @@ android:padding="0dp" android:textColor="@color/view_all_course_list_color" android:textSize="16sp" - android:visibility="visible" + android:visibility="gone" tools:ignore="MissingPrefix" tools:text="10 courses"/> From f7a8bcfeba3c9fd84510c91b5f4c1d57cf98077a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Tue, 7 Nov 2017 19:06:45 +0300 Subject: [PATCH 029/140] revert CatalogAdapter for showing course lists --- .../droid/ui/adapters/CatalogAdapter.kt | 39 +++---------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt index 6f88013945..cd1379b69f 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt @@ -7,9 +7,6 @@ import android.view.ViewGroup import kotlinx.android.synthetic.main.catalog_item.view.* import org.stepic.droid.R import org.stepic.droid.model.CourseListItem -import org.stepic.droid.model.CoursesCarouselColorType -import org.stepic.droid.model.CoursesCarouselInfo -import org.stepic.droid.storage.operations.Table class CatalogAdapter( private val courseListItems: List @@ -31,18 +28,14 @@ class CatalogAdapter( } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - (holder as CarouselViewHolder).bindData(position) -// -// when (getItemViewType(position)) { -// CAROUSEL_TYPE -> (holder as CarouselViewHolder).bindData(courseListItemBy(adapterPosition = position)) -// } + when (getItemViewType(position)) { + CAROUSEL_TYPE -> (holder as CarouselViewHolder).bindData(courseListItemBy(adapterPosition = position)) + } } - private fun courseListItemBy(adapterPosition: Int) { - courseListItems[adapterPosition] - } + private fun courseListItemBy(adapterPosition: Int): CourseListItem = courseListItems[adapterPosition] - override fun getItemCount(): Int = 10 + override fun getItemCount(): Int = courseListItems.size override fun getItemViewType(position: Int): Int = CAROUSEL_TYPE @@ -50,27 +43,7 @@ class CatalogAdapter( private val coursesCarousel = itemView.coursesCarouselItem - fun bindData(position: Int) { - val my = CoursesCarouselInfo( - CoursesCarouselColorType.Light, - itemView.resources.getString(R.string.my_courses_title), - Table.enrolled, - null) - - val popular = CoursesCarouselInfo( - CoursesCarouselColorType.Dark, - itemView.resources.getString(R.string.popular_courses_title), - Table.featured, - null) - - val info = - if (position % 2 == 0) { - my - } else { - popular - } - - coursesCarousel.setCourseCarouselInfo(info) + fun bindData(courseListItem: CourseListItem) { } From 91ab0432d13cbc9209b6f8ae3347c5dd28005078 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Tue, 7 Nov 2017 19:27:59 +0300 Subject: [PATCH 030/140] add catalog presenter --- .../droid/core/presenters/CatalogPresenter.kt | 37 +++++++++++++++++ .../core/presenters/contracts/CatalogView.kt | 10 +++++ .../org/stepic/droid/di/AppCoreComponent.kt | 3 ++ .../droid/di/catalog/CatalogComponent.kt | 16 ++++++++ .../stepic/droid/di/catalog/CatalogScope.kt | 7 ++++ .../droid/ui/fragments/CatalogFragment.kt | 41 ++++++++++++++++++- .../main/java/org/stepic/droid/web/Api.java | 4 +- .../java/org/stepic/droid/web/ApiImpl.java | 2 +- .../droid/web/StepicRestLoggedService.java | 2 +- 9 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt create mode 100644 app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt create mode 100644 app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt create mode 100644 app/src/main/java/org/stepic/droid/di/catalog/CatalogScope.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt new file mode 100644 index 0000000000..c29980e41d --- /dev/null +++ b/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt @@ -0,0 +1,37 @@ +package org.stepic.droid.core.presenters + +import io.reactivex.Scheduler +import org.stepic.droid.core.presenters.contracts.CatalogView +import org.stepic.droid.di.catalog.CatalogScope +import org.stepic.droid.di.qualifiers.BackgroundScheduler +import org.stepic.droid.di.qualifiers.MainScheduler +import org.stepic.droid.web.Api +import javax.inject.Inject + +@CatalogScope +class CatalogPresenter +@Inject +constructor( + private val api: Api, + @BackgroundScheduler + private val backgroundScheduler: Scheduler, + @MainScheduler + private val mainScheduler: Scheduler +) : PresenterBase() { + + fun onCatalogOpened() { + api + .courseLists + .map { + it.courseLists + } + .subscribeOn(backgroundScheduler) + .observeOn(mainScheduler) + .subscribe({ + view?.showCourseItems(it) + }, { + view?.offlineMode() + }) + + } +} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt new file mode 100644 index 0000000000..e4fd06dddf --- /dev/null +++ b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt @@ -0,0 +1,10 @@ +package org.stepic.droid.core.presenters.contracts + +import org.stepic.droid.model.CourseListItem + +interface CatalogView { + + fun showCourseItems(courseItems: List) + + fun offlineMode() +} diff --git a/app/src/main/java/org/stepic/droid/di/AppCoreComponent.kt b/app/src/main/java/org/stepic/droid/di/AppCoreComponent.kt index 81e833ec0f..7ce7db27fb 100644 --- a/app/src/main/java/org/stepic/droid/di/AppCoreComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/AppCoreComponent.kt @@ -7,6 +7,7 @@ import org.stepic.droid.base.App import org.stepic.droid.base.FragmentActivityBase import org.stepic.droid.base.FragmentBase import org.stepic.droid.code.ui.CodeEditor +import org.stepic.droid.di.catalog.CatalogComponent import org.stepic.droid.di.certificates.CertificateComponent import org.stepic.droid.di.course_general.CourseGeneralComponent import org.stepic.droid.di.downloads.DownloadsComponent @@ -75,6 +76,8 @@ interface AppCoreComponent { fun routingComponentBuilder(): RoutingComponent.Builder + fun catalogComponentBuilder(): CatalogComponent.Builder + fun inject(someActivity: FragmentActivityBase) fun inject(adapter: CoursesAdapter) diff --git a/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt b/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt new file mode 100644 index 0000000000..f72fd23952 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt @@ -0,0 +1,16 @@ +package org.stepic.droid.di.catalog + +import dagger.Subcomponent +import org.stepic.droid.ui.fragments.CatalogFragment + +@CatalogScope +@Subcomponent +interface CatalogComponent { + + @Subcomponent.Builder + interface Builder { + fun build(): CatalogComponent + } + + fun inject(catalogFragment: CatalogFragment) +} diff --git a/app/src/main/java/org/stepic/droid/di/catalog/CatalogScope.kt b/app/src/main/java/org/stepic/droid/di/catalog/CatalogScope.kt new file mode 100644 index 0000000000..3db95bbb9c --- /dev/null +++ b/app/src/main/java/org/stepic/droid/di/catalog/CatalogScope.kt @@ -0,0 +1,7 @@ +package org.stepic.droid.di.catalog + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class CatalogScope diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt index 1c42a7b07c..90a821551e 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -7,17 +7,36 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_catalog.* import org.stepic.droid.R +import org.stepic.droid.base.App import org.stepic.droid.base.FragmentBase +import org.stepic.droid.core.presenters.CatalogPresenter +import org.stepic.droid.core.presenters.contracts.CatalogView import org.stepic.droid.model.CourseListItem import org.stepic.droid.ui.adapters.CatalogAdapter import org.stepic.droid.ui.util.initCenteredToolbar +import javax.inject.Inject -class CatalogFragment : FragmentBase() { +class CatalogFragment : FragmentBase(), + CatalogView { companion object { fun newInstance(): FragmentBase = CatalogFragment() } + @Inject + lateinit var catalogPresenter: CatalogPresenter + + private val courseItems = mutableListOf() + + override fun injectComponent() { + App + .Companion + .component() + .catalogComponentBuilder() + .build() + .inject(this) + } + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater?.inflate(R.layout.fragment_catalog, container, false) @@ -27,11 +46,29 @@ class CatalogFragment : FragmentBase() { initCenteredToolbar(R.string.catalog_title, showHomeButton = false) initMainRecycler() + + catalogPresenter.attachView(this) + catalogPresenter.onCatalogOpened() + } + + override fun onDestroyView() { + super.onDestroyView() + catalogPresenter.detachView(this) } private fun initMainRecycler() { catalogRecyclerView.layoutManager = LinearLayoutManager(context) - catalogRecyclerView.adapter = CatalogAdapter(emptyList()) + catalogRecyclerView.adapter = CatalogAdapter(courseItems) + } + + override fun showCourseItems(courseItems: List) { + this.courseItems.clear() + this.courseItems.addAll(courseItems) + catalogRecyclerView.adapter.notifyDataSetChanged() + } + + override fun offlineMode() { + //do nothing } } diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index f458003728..76fab75658 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -52,7 +52,7 @@ enum TokenType { Call getSteps(long[] steps); - Single getStepsReactive (long [] steps); + Single getStepsReactive(long[] steps); @Nullable Call dropCourse(long courseId); @@ -121,5 +121,5 @@ enum TokenType { Call getLastStepResponse(@NotNull String lastStepId); - Call getCourseLists (); + Single getCourseLists(); } diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 6a5da014c3..46e1f6ff68 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -744,7 +744,7 @@ public Call getLastStepResponse(@NonNull String lastStepId) { } @Override - public Call getCourseLists() { + public Single getCourseLists() { //// TODO: 26.09.2017 determine language of course list for not native russian speakers String language = "ru"; return loggedService.getCourseLists(language); diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index 220e4dcdab..9831b17f93 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -140,5 +140,5 @@ Call getSearchResults(@Query("page") int page, Call getLastStepResponse(@Path("lastStepId") String lastStepId); @GET("api/course-lists?platform=mobile") - Call getCourseLists(@Query("language") String language); + Single getCourseLists(@Query("language") String language); } From 423a3f721bfbdae23ab3dd2726649f95effe094a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Tue, 7 Nov 2017 20:33:49 +0300 Subject: [PATCH 031/140] show course lists in catalog --- .../droid/core/presenters/CatalogPresenter.kt | 10 +++-- .../core/presenters/CourseListCollection.kt | 43 +++++++++++++++++++ .../core/presenters/contracts/CatalogView.kt | 4 +- .../droid/di/catalog/CatalogComponent.kt | 2 +- .../stepic/droid/di/catalog/CatalogModule.kt | 15 +++++++ .../mappers/CourseItemToCarouselInfoMapper.kt | 20 +++++++++ .../java/org/stepic/droid/mappers/Mapper.kt | 17 ++------ .../org/stepic/droid/model/CourseListItem.kt | 4 +- .../stepic/droid/model/CoursesCarouselInfo.kt | 28 +++++++++++- .../droid/ui/adapters/CatalogAdapter.kt | 11 +++-- .../droid/ui/custom/CoursesCarouselView.kt | 11 ++++- .../droid/ui/fragments/CatalogFragment.kt | 12 +++--- .../main/java/org/stepic/droid/web/Api.java | 2 + .../java/org/stepic/droid/web/ApiImpl.java | 8 ++++ .../droid/web/StepicRestLoggedService.java | 3 ++ .../droid/model/CoursesCarouselInfoTest.kt | 16 +++++++ 16 files changed, 169 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt create mode 100644 app/src/main/java/org/stepic/droid/di/catalog/CatalogModule.kt create mode 100644 app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt create mode 100644 app/src/test/java/org/stepic/droid/model/CoursesCarouselInfoTest.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt index c29980e41d..b316015f02 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/CatalogPresenter.kt @@ -5,6 +5,9 @@ import org.stepic.droid.core.presenters.contracts.CatalogView import org.stepic.droid.di.catalog.CatalogScope import org.stepic.droid.di.qualifiers.BackgroundScheduler import org.stepic.droid.di.qualifiers.MainScheduler +import org.stepic.droid.mappers.Mapper +import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselInfo import org.stepic.droid.web.Api import javax.inject.Inject @@ -16,19 +19,20 @@ constructor( @BackgroundScheduler private val backgroundScheduler: Scheduler, @MainScheduler - private val mainScheduler: Scheduler + private val mainScheduler: Scheduler, + private val mapper: Mapper ) : PresenterBase() { fun onCatalogOpened() { api .courseLists .map { - it.courseLists + mapper.map(it.courseLists) } .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) .subscribe({ - view?.showCourseItems(it) + view?.showCarousels(it) }, { view?.offlineMode() }) diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt b/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt new file mode 100644 index 0000000000..786940e716 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt @@ -0,0 +1,43 @@ +package org.stepic.droid.core.presenters + +import io.reactivex.Scheduler +import org.stepic.droid.core.presenters.contracts.CoursesView +import org.stepic.droid.di.course_list.CourseListScope +import org.stepic.droid.di.qualifiers.BackgroundScheduler +import org.stepic.droid.di.qualifiers.MainScheduler +import org.stepic.droid.web.Api +import javax.inject.Inject + +@CourseListScope +class CourseListCollection +@Inject +constructor( + @BackgroundScheduler + private val backgroundScheduler: Scheduler, + @MainScheduler + private val mainScheduler: Scheduler, + private val api: Api +) : PresenterBase() { + + companion object { + //collections are small (<10 courses), so pagination is not needed + private val DEFAULT_PAGE = 1 + } + + fun onShowCollection(courseIds: LongArray) { + //todo add progresses and ratings, when it will be implemented. + view?.showLoading() + api + .getCoursesReactive(DEFAULT_PAGE, courseIds) + .map { it.courses } + .subscribeOn(backgroundScheduler) + .observeOn(mainScheduler) + .subscribe({ + view?.showCourses(it) + }, { + view?.showConnectionProblem() + }) + + } + +} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt index e4fd06dddf..e57f4dc548 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CatalogView.kt @@ -1,10 +1,10 @@ package org.stepic.droid.core.presenters.contracts -import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselInfo interface CatalogView { - fun showCourseItems(courseItems: List) + fun showCarousels(courseItems: List) fun offlineMode() } diff --git a/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt b/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt index f72fd23952..19bcbd2fee 100644 --- a/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/catalog/CatalogComponent.kt @@ -4,7 +4,7 @@ import dagger.Subcomponent import org.stepic.droid.ui.fragments.CatalogFragment @CatalogScope -@Subcomponent +@Subcomponent(modules = arrayOf(CatalogModule::class)) interface CatalogComponent { @Subcomponent.Builder diff --git a/app/src/main/java/org/stepic/droid/di/catalog/CatalogModule.kt b/app/src/main/java/org/stepic/droid/di/catalog/CatalogModule.kt new file mode 100644 index 0000000000..86a53796a2 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/di/catalog/CatalogModule.kt @@ -0,0 +1,15 @@ +package org.stepic.droid.di.catalog + +import dagger.Binds +import dagger.Module +import org.stepic.droid.mappers.CourseItemToCarouselInfoMapper +import org.stepic.droid.mappers.Mapper +import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselInfo + +@Module +interface CatalogModule { + + @Binds + fun bindMapper(courseListToCarouselInfoMapper: CourseItemToCarouselInfoMapper): Mapper +} diff --git a/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt b/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt new file mode 100644 index 0000000000..473ebc9c3a --- /dev/null +++ b/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt @@ -0,0 +1,20 @@ +package org.stepic.droid.mappers + +import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselColorType +import org.stepic.droid.model.CoursesCarouselInfo +import javax.inject.Inject + +class CourseItemToCarouselInfoMapper +@Inject +constructor() : Mapper { + + override fun map(item: CourseListItem): CoursesCarouselInfo { + return CoursesCarouselInfo( + colorType = CoursesCarouselColorType.Light, + title = item.title, + table = null, + courseIds = item.courses + ) + } +} diff --git a/app/src/main/java/org/stepic/droid/mappers/Mapper.kt b/app/src/main/java/org/stepic/droid/mappers/Mapper.kt index 658266c4f5..1222557c4c 100644 --- a/app/src/main/java/org/stepic/droid/mappers/Mapper.kt +++ b/app/src/main/java/org/stepic/droid/mappers/Mapper.kt @@ -1,17 +1,8 @@ package org.stepic.droid.mappers +//dagger 2 cannot find class with "in S" +interface Mapper { + fun map(item: S): D -/** - * this class is ok, when we don't need some extra information - */ -interface Mapper { - fun S.to(): D - - fun List.to(): List { - val result = ArrayList() - this.forEach { - result.add(it.to()) - } - return result - } + fun map(sourceList: List): List = sourceList.map { map(it) } } diff --git a/app/src/main/java/org/stepic/droid/model/CourseListItem.kt b/app/src/main/java/org/stepic/droid/model/CourseListItem.kt index 25e83463cb..4261288ec2 100644 --- a/app/src/main/java/org/stepic/droid/model/CourseListItem.kt +++ b/app/src/main/java/org/stepic/droid/model/CourseListItem.kt @@ -5,9 +5,9 @@ import java.util.* data class CourseListItem( private val id: Long, private val position: Int, - private val title: String, + val title: String, private val language: String, - private val courses: LongArray + val courses: LongArray ) { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt b/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt index 2681178995..656f6a6c07 100644 --- a/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt +++ b/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt @@ -3,6 +3,7 @@ package org.stepic.droid.model import android.os.Parcel import android.os.Parcelable import org.stepic.droid.storage.operations.Table +import java.util.* data class CoursesCarouselInfo( val colorType: CoursesCarouselColorType, @@ -11,7 +12,7 @@ data class CoursesCarouselInfo( val courseIds: LongArray? ) : Parcelable { - constructor(source: Parcel) : this( + private constructor(source: Parcel) : this( source.readParcelable(CoursesCarouselColorType::class.java.classLoader), source.readString(), source.readParcelable(Table::class.java.classLoader), @@ -28,10 +29,33 @@ data class CoursesCarouselInfo( } companion object { + @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { override fun createFromParcel(source: Parcel): CoursesCarouselInfo = CoursesCarouselInfo(source) override fun newArray(size: Int): Array = arrayOfNulls(size) } } -} \ No newline at end of file + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CoursesCarouselInfo + + if (colorType != other.colorType) return false + if (title != other.title) return false + if (table != other.table) return false + if (!Arrays.equals(courseIds, other.courseIds)) return false + + return true + } + + override fun hashCode(): Int { + var result = colorType.hashCode() + result = 31 * result + title.hashCode() + result = 31 * result + (table?.hashCode() ?: 0) + result = 31 * result + (courseIds?.let { Arrays.hashCode(it) } ?: 0) + return result + } +} diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt index cd1379b69f..66586e8631 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt @@ -6,10 +6,10 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.catalog_item.view.* import org.stepic.droid.R -import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselInfo class CatalogAdapter( - private val courseListItems: List + private val courseListItems: List ) : RecyclerView.Adapter() { companion object { @@ -33,7 +33,7 @@ class CatalogAdapter( } } - private fun courseListItemBy(adapterPosition: Int): CourseListItem = courseListItems[adapterPosition] + private fun courseListItemBy(adapterPosition: Int): CoursesCarouselInfo = courseListItems[adapterPosition] override fun getItemCount(): Int = courseListItems.size @@ -43,9 +43,8 @@ class CatalogAdapter( private val coursesCarousel = itemView.coursesCarouselItem - fun bindData(courseListItem: CourseListItem) { - - + fun bindData(coursesCarouselInfo: CoursesCarouselInfo) { + coursesCarousel.setCourseCarouselInfo(coursesCarouselInfo) } } diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index 24be22b6f4..86542355dc 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -21,6 +21,7 @@ import org.stepic.droid.core.ScreenManager import org.stepic.droid.core.dropping.contract.DroppingListener import org.stepic.droid.core.joining.contract.JoiningListener import org.stepic.droid.core.presenters.ContinueCoursePresenter +import org.stepic.droid.core.presenters.CourseListCollection import org.stepic.droid.core.presenters.DroppingPresenter import org.stepic.droid.core.presenters.PersistentCourseListPresenter import org.stepic.droid.core.presenters.contracts.ContinueCourseView @@ -86,6 +87,9 @@ constructor( @Inject lateinit var analytic: Analytic + @Inject + lateinit var courseListCollection: CourseListCollection + private val courses = ArrayList() private var lastSavedScrollPosition: Int = DEFAULT_SCROLL_POSITION @@ -146,6 +150,7 @@ constructor( droppingPresenter.attachView(this) droppingClient.subscribe(this) joiningListenerClient.subscribe(this) + courseListCollection.attachView(this) if (needExecuteOnInfoInitialized) { onInfoInitialized(info) @@ -155,6 +160,7 @@ constructor( override fun onDetachedFromWindow() { super.onDetachedFromWindow() + courseListCollection.detachView(this) joiningListenerClient.unsubscribe(this) droppingClient.unsubscribe(this) continueCoursePresenter.detachView(this) @@ -210,7 +216,6 @@ constructor( } override fun showLoading() { - Timber.d("show loading") coursesViewAll.visibility = View.GONE coursesRecycler.visibility = View.GONE coursesPlaceholder.visibility = View.GONE @@ -340,7 +345,9 @@ constructor( } if (info.table == null) { - // TODO: 26.09.2017 implement course list fetching (presenter and view : CoursesView) + info.courseIds?.let { + courseListCollection.onShowCollection(it) + } } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt index 90a821551e..e16852b0a0 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -11,7 +11,7 @@ import org.stepic.droid.base.App import org.stepic.droid.base.FragmentBase import org.stepic.droid.core.presenters.CatalogPresenter import org.stepic.droid.core.presenters.contracts.CatalogView -import org.stepic.droid.model.CourseListItem +import org.stepic.droid.model.CoursesCarouselInfo import org.stepic.droid.ui.adapters.CatalogAdapter import org.stepic.droid.ui.util.initCenteredToolbar import javax.inject.Inject @@ -26,7 +26,7 @@ class CatalogFragment : FragmentBase(), @Inject lateinit var catalogPresenter: CatalogPresenter - private val courseItems = mutableListOf() + private val courseCarouselInfoList = mutableListOf() override fun injectComponent() { App @@ -58,12 +58,12 @@ class CatalogFragment : FragmentBase(), private fun initMainRecycler() { catalogRecyclerView.layoutManager = LinearLayoutManager(context) - catalogRecyclerView.adapter = CatalogAdapter(courseItems) + catalogRecyclerView.adapter = CatalogAdapter(courseCarouselInfoList) } - override fun showCourseItems(courseItems: List) { - this.courseItems.clear() - this.courseItems.addAll(courseItems) + override fun showCarousels(courseItems: List) { + this.courseCarouselInfoList.clear() + this.courseCarouselInfoList.addAll(courseItems) catalogRecyclerView.adapter.notifyDataSetChanged() } diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index 76fab75658..87fbb128c6 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -69,6 +69,8 @@ enum TokenType { Call getCourses(int page, long[] ids); + Single getCoursesReactive(int page, @NotNull long[] ids); + Call createNewAttempt(long stepId); Call createNewSubmission(Reply reply, long attemptId); diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 46e1f6ff68..8f39a58646 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -513,6 +513,14 @@ public Call getCourses(int page, @Nullable long[] ids) { return loggedService.getCourses(page, ids); } + @Override + public Single getCoursesReactive(int page, @NotNull long[] ids) { + if (ids.length == 0) { + ids = new long[]{0}; + } + return loggedService.getCoursesReactive(page, ids); + } + @Override public Call createNewAttempt(long stepId) { AttemptRequest attemptRequest = new AttemptRequest(stepId); diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index 9831b17f93..2b027a4a9e 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -69,6 +69,9 @@ Call getSearchResults(@Query("page") int page, @GET("api/courses") Call getCourses(@Query("page") int page, @Query("ids[]") long[] courseIds); + @GET("api/courses") + Single getCoursesReactive(@Query("page") int page, @Query("ids[]") long[] courseIds); + @POST("api/attempts") Call createNewAttempt(@Body AttemptRequest attemptRequest); diff --git a/app/src/test/java/org/stepic/droid/model/CoursesCarouselInfoTest.kt b/app/src/test/java/org/stepic/droid/model/CoursesCarouselInfoTest.kt new file mode 100644 index 0000000000..06a48623b8 --- /dev/null +++ b/app/src/test/java/org/stepic/droid/model/CoursesCarouselInfoTest.kt @@ -0,0 +1,16 @@ +package org.stepic.droid.model + +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.stepic.droid.testUtils.assertThatObjectParcelable + +@RunWith(RobolectricTestRunner::class) +class CoursesCarouselInfoTest { + + @Test + fun infoIsParcelable() { + val info = CoursesCarouselInfo(CoursesCarouselColorType.Light, "hello", null, longArrayOf(1, 3, 10)) + info.assertThatObjectParcelable() + } +} From e9a47c3f81696b5ee1da76c96f7e8f02fb1186a3 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 10:25:33 +0300 Subject: [PATCH 032/140] filter courses in editor collection --- .../stepic/droid/core/presenters/CourseListCollection.kt | 9 ++++++++- .../droid/core/presenters/contracts/CoursesView.kt | 2 +- .../org/stepic/droid/ui/custom/CoursesCarouselView.kt | 2 +- .../stepic/droid/ui/fragments/FastContinueFragment.kt | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt b/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt index 786940e716..0021b4f8d3 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/CourseListCollection.kt @@ -29,7 +29,14 @@ constructor( view?.showLoading() api .getCoursesReactive(DEFAULT_PAGE, courseIds) - .map { it.courses } + .map { + val coursesMap = it.courses.associateBy { it.courseId } + courseIds + .asIterable() + .mapNotNull { + coursesMap[it] + } + } .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) .subscribe({ diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/CoursesView.kt b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CoursesView.kt index e0b6fcb89b..03d434dacb 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/contracts/CoursesView.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/contracts/CoursesView.kt @@ -9,5 +9,5 @@ interface CoursesView { fun showConnectionProblem() - fun showCourses(courses: MutableList) + fun showCourses(courses: List) } diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index 86542355dc..c4920c6a37 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -264,7 +264,7 @@ constructor( } } - override fun showCourses(courses: MutableList) { + override fun showCourses(courses: List) { coursesLoadingView.visibility = View.GONE coursesPlaceholder.visibility = View.GONE if (lastSavedScrollPosition != DEFAULT_SCROLL_POSITION) { diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt index 755829be6f..6298a48e5b 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt @@ -154,7 +154,7 @@ class FastContinueFragment : FragmentBase(), }) } - override fun showCourses(courses: MutableList) { + override fun showCourses(courses: List) { fastContinueProgress.visibility = View.GONE fastContinuePlaceholder.visibility = View.GONE showMainGroup(true) From dbf8d7e323f47cd1c4e938b4c5c3d34f17daae2a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 10:46:00 +0300 Subject: [PATCH 033/140] add max lines 3 to course widget, 64 symbols can going to 5 lines like in this course https://stepik.org/course/88/ --- app/src/main/res/layout/new_course_item.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/new_course_item.xml b/app/src/main/res/layout/new_course_item.xml index cf2d1ae99c..bd069c237e 100644 --- a/app/src/main/res/layout/new_course_item.xml +++ b/app/src/main/res/layout/new_course_item.xml @@ -16,8 +16,8 @@ Date: Wed, 8 Nov 2017 11:19:18 +0300 Subject: [PATCH 034/140] fix view all for course collections --- .../di/course_list/CourseListComponent.kt | 5 +- .../droid/ui/activities/CourseListActivity.kt | 14 ++-- .../ui/fragments/CourseCollectionFragment.kt | 64 +++++++++++++++++++ .../ui/fragments/CourseListFragmentBase.java | 1 + .../ui/fragments/CourseSearchFragment.java | 1 - .../ui/fragments/FindCoursesFragment.java | 6 +- .../fragments/PopularCoursesAloneFragment.kt | 4 +- 7 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/CourseCollectionFragment.kt diff --git a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt index 162d88883e..c4f214d673 100644 --- a/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/course_list/CourseListComponent.kt @@ -2,9 +2,10 @@ package org.stepic.droid.di.course_list import dagger.Subcomponent import org.stepic.droid.base.CoursesDatabaseFragmentBase +import org.stepic.droid.ui.custom.CoursesCarouselView +import org.stepic.droid.ui.fragments.CourseCollectionFragment import org.stepic.droid.ui.fragments.CourseListFragmentBase import org.stepic.droid.ui.fragments.CourseSearchFragment -import org.stepic.droid.ui.custom.CoursesCarouselView import org.stepic.droid.ui.fragments.FastContinueFragment @CourseListScope @@ -21,6 +22,8 @@ interface CourseListComponent { fun inject(fragment: CourseListFragmentBase) + fun inject(fragment: CourseCollectionFragment) + fun inject(fragment: CourseSearchFragment) fun inject(view: CoursesCarouselView) diff --git a/app/src/main/java/org/stepic/droid/ui/activities/CourseListActivity.kt b/app/src/main/java/org/stepic/droid/ui/activities/CourseListActivity.kt index 053f5b945d..8a1f5da3e9 100644 --- a/app/src/main/java/org/stepic/droid/ui/activities/CourseListActivity.kt +++ b/app/src/main/java/org/stepic/droid/ui/activities/CourseListActivity.kt @@ -4,18 +4,20 @@ import android.support.v4.app.Fragment import org.stepic.droid.base.SingleFragmentActivity import org.stepic.droid.model.CoursesCarouselInfo import org.stepic.droid.storage.operations.Table +import org.stepic.droid.ui.fragments.CourseCollectionFragment import org.stepic.droid.ui.fragments.MyCoursesFragment import org.stepic.droid.ui.fragments.PopularCoursesAloneFragment class CourseListActivity : SingleFragmentActivity() { override fun createFragment(): Fragment { val info = intent.getParcelableExtra(COURSE_LIST_INFO_KEY) - if (info.table == Table.enrolled) { - return MyCoursesFragment.newInstance() - } else if (info.table == Table.featured) { - return PopularCoursesAloneFragment.newInstance() - } else { - throw IllegalStateException("course lists are not supported yet") + return when { + info.table == Table.enrolled -> MyCoursesFragment.newInstance() + info.table == Table.featured -> PopularCoursesAloneFragment.newInstance() + info.table == null && info.courseIds != null -> { + CourseCollectionFragment.newInstance(info.title, info.courseIds) + } + else -> throw IllegalStateException("course info is broken") } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseCollectionFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CourseCollectionFragment.kt new file mode 100644 index 0000000000..d12698e5d7 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseCollectionFragment.kt @@ -0,0 +1,64 @@ +package org.stepic.droid.ui.fragments + +import android.os.Bundle +import android.view.View +import org.stepic.droid.base.App +import org.stepic.droid.core.presenters.CourseListCollection +import org.stepic.droid.storage.operations.Table +import org.stepic.droid.ui.util.initCenteredToolbar +import javax.inject.Inject + +class CourseCollectionFragment : CourseListFragmentBase() { + companion object { + private const val TITLE_KEY = "title_key" + private const val COURSE_IDS = "course_ids" + + fun newInstance(title: String, courseIds: LongArray): CourseCollectionFragment { + val args = Bundle().apply { + putString(TITLE_KEY, title) + putLongArray(COURSE_IDS, courseIds) + } + return CourseCollectionFragment().apply { arguments = args } + } + } + + @Inject + lateinit var courseListCollection: CourseListCollection + + override fun injectComponent() { + App + .componentManager() + .courseGeneralComponent() + .courseListComponentBuilder() + .build() + .inject(this) + } + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initCenteredToolbar(getTitle()) + courseListCollection.attachView(this) + courseListCollection.onShowCollection(arguments.getLongArray(COURSE_IDS)) + } + + override fun onDestroy() { + super.onDestroy() + courseListCollection.detachView(this) + } + + override fun onRefresh() { + courseListCollection.onShowCollection(arguments.getLongArray(COURSE_IDS)) + } + + override fun getCourseType(): Table? = null + + override fun onNeedDownloadNextPage() { + //no op + } + + override fun showEmptyScreen(isShow: Boolean) { + + } + + fun getTitle(): String = arguments.getString(TITLE_KEY) +} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java b/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java index 9589180b7d..af6b6165d7 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseListFragmentBase.java @@ -203,6 +203,7 @@ public void onDestroyView() { super.onDestroyView(); } + @Nullable protected abstract Table getCourseType(); public final void updateEnrollment(Course courseForUpdate, long enrollment) { diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java index 4c40a719cd..8dbaae316d 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CourseSearchFragment.java @@ -84,7 +84,6 @@ public void showEmptyScreen(boolean isShowed) { } else { emptySearch.setVisibility(View.GONE); swipeRefreshLayout.setVisibility(View.VISIBLE); - } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java index cec2cc9e11..a1567e0249 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java @@ -6,7 +6,6 @@ import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.annotation.StringRes; import android.support.v4.content.ContextCompat; import android.support.v7.widget.SearchView; import android.view.Menu; @@ -118,8 +117,7 @@ public void onDestroyOptionsMenu() { searchView = null; } - @StringRes - protected int getTitle () { - return R.string.catalog_title; + protected String getTitle () { + return getString(R.string.catalog_title); } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt index ce2fc19a8c..1ca0c05520 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt @@ -4,7 +4,7 @@ import android.view.Menu import android.view.MenuInflater import org.stepic.droid.R -class PopularCoursesAloneFragment : FindCoursesFragment() { +open class PopularCoursesAloneFragment : FindCoursesFragment() { companion object { fun newInstance(): PopularCoursesAloneFragment = PopularCoursesAloneFragment() } @@ -13,5 +13,5 @@ class PopularCoursesAloneFragment : FindCoursesFragment() { //no-op } - override fun getTitle(): Int = R.string.popular_courses_title + override fun getTitle(): String = getString(R.string.popular_courses_title) } From 33af70c4a9416af68e5831813f0e60ed57b021bb Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 11:41:58 +0300 Subject: [PATCH 035/140] make Placeholder Tex View customizable --- .../droid/ui/custom/PlaceholderTextView.kt | 29 ++++++++++--------- app/src/main/res/values/attrs.xml | 5 ++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/custom/PlaceholderTextView.kt b/app/src/main/java/org/stepic/droid/ui/custom/PlaceholderTextView.kt index 23eeca72e3..f5dcfb1058 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/PlaceholderTextView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/PlaceholderTextView.kt @@ -17,20 +17,18 @@ import uk.co.chrisjenx.calligraphy.CalligraphyTypefaceSpan import uk.co.chrisjenx.calligraphy.TypefaceUtils import javax.inject.Inject -class PlaceholderTextView : android.support.v7.widget.AppCompatTextView { - - constructor(context: Context) : this(context, null) - - constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init() - } +class PlaceholderTextView +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : android.support.v7.widget.AppCompatTextView(context, attrs, defStyleAttr) { @Inject lateinit var fontsProvider: FontsProvider - private fun init() { + init { App.component().inject(this) val sidePadding = resources.getDimensionPixelSize(R.dimen.placeholder_side_padding) @@ -41,10 +39,15 @@ class PlaceholderTextView : android.support.v7.widget.AppCompatTextView { val defaultLineSpacingMultiplier = 1.0f setLineSpacing(resources.getDimension(R.dimen.placeholder_line_spacing_extra), defaultLineSpacingMultiplier) - setTextColor(ColorUtil.getColorArgb(R.color.placeholder_text_color, this.context)) - setBackgroundResource(R.drawable.gradient_background) - gravity = Gravity.CENTER_VERTICAL + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PlaceholderTextView) + try { + setBackgroundResource(typedArray.getResourceId(R.styleable.PlaceholderTextView_android_background, R.drawable.gradient_background)) + gravity = typedArray.getInt(R.styleable.PlaceholderTextView_android_gravity, Gravity.CENTER_VERTICAL) + } finally { + typedArray.recycle() + } } diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 64c506094a..3ed1e6978c 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -78,4 +78,9 @@ + + + + + \ No newline at end of file From 260927227e94d1e98b5f8c2d2ed4e50dd7b6e98f Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 11:53:21 +0300 Subject: [PATCH 036/140] add blue gradient --- .../main/res/drawable/gradient_background_blue.xml | 13 +++++++++++++ app/src/main/res/values/colors.xml | 3 +++ 2 files changed, 16 insertions(+) create mode 100644 app/src/main/res/drawable/gradient_background_blue.xml diff --git a/app/src/main/res/drawable/gradient_background_blue.xml b/app/src/main/res/drawable/gradient_background_blue.xml new file mode 100644 index 0000000000..f84e40e0d6 --- /dev/null +++ b/app/src/main/res/drawable/gradient_background_blue.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2c88850ff5..bad17825fb 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -118,6 +118,9 @@ #6969A0 @color/white + #D7E1E7 + #E1E8EF + #F6F7F9 #DBDBDB From 7f72e0920562075b18351b48f59277b52d52859d Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 11:57:21 +0300 Subject: [PATCH 037/140] add fire gradient --- .../main/res/drawable/gradient_background_fire.xml | 14 ++++++++++++++ app/src/main/res/values/colors.xml | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 app/src/main/res/drawable/gradient_background_fire.xml diff --git a/app/src/main/res/drawable/gradient_background_fire.xml b/app/src/main/res/drawable/gradient_background_fire.xml new file mode 100644 index 0000000000..15d892be68 --- /dev/null +++ b/app/src/main/res/drawable/gradient_background_fire.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bad17825fb..9749bae988 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -121,6 +121,10 @@ #D7E1E7 #E1E8EF + #D4D0D9 + #EDDFEB + #F5DEDC + #F6F7F9 #DBDBDB From 05242ab27fcdbac5ae681169bc1a794bbb473839 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 8 Nov 2017 12:42:15 +0300 Subject: [PATCH 038/140] search suggestions layout --- .../drawable-v21/search_query_background.xml | 9 +++++++ .../res/drawable/search_query_background.xml | 13 +++++++++ .../layout/search_queries_recycler_view.xml | 8 ++++++ app/src/main/res/layout/search_query_item.xml | 27 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 app/src/main/res/drawable-v21/search_query_background.xml create mode 100644 app/src/main/res/drawable/search_query_background.xml create mode 100755 app/src/main/res/layout/search_queries_recycler_view.xml create mode 100755 app/src/main/res/layout/search_query_item.xml diff --git a/app/src/main/res/drawable-v21/search_query_background.xml b/app/src/main/res/drawable-v21/search_query_background.xml new file mode 100644 index 0000000000..d7ce237b42 --- /dev/null +++ b/app/src/main/res/drawable-v21/search_query_background.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_query_background.xml b/app/src/main/res/drawable/search_query_background.xml new file mode 100644 index 0000000000..1bb141bc90 --- /dev/null +++ b/app/src/main/res/drawable/search_query_background.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_queries_recycler_view.xml b/app/src/main/res/layout/search_queries_recycler_view.xml new file mode 100755 index 0000000000..cae264b6cb --- /dev/null +++ b/app/src/main/res/layout/search_queries_recycler_view.xml @@ -0,0 +1,8 @@ + + diff --git a/app/src/main/res/layout/search_query_item.xml b/app/src/main/res/layout/search_query_item.xml new file mode 100755 index 0000000000..ac075fd691 --- /dev/null +++ b/app/src/main/res/layout/search_query_item.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file From 83a454b5c6fb00513c5fbe9040866b6f20d91ce8 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 12:38:10 +0300 Subject: [PATCH 039/140] add course list description --- .../mappers/CourseItemToCarouselInfoMapper.kt | 3 ++- .../model/CollectionDescriptionColors.kt | 16 ++++++++++++++++ .../org/stepic/droid/model/CourseListItem.kt | 3 ++- .../stepic/droid/model/CoursesCarouselInfo.kt | 3 ++- .../droid/ui/adapters/CatalogAdapter.kt | 18 ++++++++++++++++-- .../droid/ui/custom/CoursesCarouselView.kt | 19 +++++++++++++++++-- .../res/drawable/gradient_background_blue.xml | 2 +- .../res/drawable/gradient_background_fire.xml | 2 +- app/src/main/res/values/colors.xml | 14 ++++++++------ app/src/main/res/values/integers.xml | 1 + 10 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/model/CollectionDescriptionColors.kt diff --git a/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt b/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt index 473ebc9c3a..a81f4badd6 100644 --- a/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt +++ b/app/src/main/java/org/stepic/droid/mappers/CourseItemToCarouselInfoMapper.kt @@ -14,7 +14,8 @@ constructor() : Mapper { colorType = CoursesCarouselColorType.Light, title = item.title, table = null, - courseIds = item.courses + courseIds = item.courses, + description = item.description ) } } diff --git a/app/src/main/java/org/stepic/droid/model/CollectionDescriptionColors.kt b/app/src/main/java/org/stepic/droid/model/CollectionDescriptionColors.kt new file mode 100644 index 0000000000..582e8ce3d2 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/model/CollectionDescriptionColors.kt @@ -0,0 +1,16 @@ +package org.stepic.droid.model + +import android.support.annotation.ColorRes +import android.support.annotation.DrawableRes +import org.stepic.droid.R + +enum class CollectionDescriptionColors( + @DrawableRes + val backgroundRes: Int, + @ColorRes + val textColorRes: Int +) { + BLUE(R.drawable.gradient_background_blue, R.color.text_color_gradient_blue), + FIRE(R.drawable.gradient_background_fire, R.color.text_color_gradient_fire) + +} diff --git a/app/src/main/java/org/stepic/droid/model/CourseListItem.kt b/app/src/main/java/org/stepic/droid/model/CourseListItem.kt index 4261288ec2..bd6ed1b84e 100644 --- a/app/src/main/java/org/stepic/droid/model/CourseListItem.kt +++ b/app/src/main/java/org/stepic/droid/model/CourseListItem.kt @@ -7,7 +7,8 @@ data class CourseListItem( private val position: Int, val title: String, private val language: String, - val courses: LongArray + val courses: LongArray, + val description: String ) { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt b/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt index 656f6a6c07..0c33224fe5 100644 --- a/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt +++ b/app/src/main/java/org/stepic/droid/model/CoursesCarouselInfo.kt @@ -9,7 +9,8 @@ data class CoursesCarouselInfo( val colorType: CoursesCarouselColorType, val title: String, val table: Table?, //if null -> see courseIds:LongArray - val courseIds: LongArray? + val courseIds: LongArray?, + val description: String = "" ) : Parcelable { private constructor(source: Parcel) : this( diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt index 66586e8631..f62ca78092 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/CatalogAdapter.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.catalog_item.view.* import org.stepic.droid.R +import org.stepic.droid.model.CollectionDescriptionColors import org.stepic.droid.model.CoursesCarouselInfo class CatalogAdapter( @@ -29,10 +30,22 @@ class CatalogAdapter( override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (getItemViewType(position)) { - CAROUSEL_TYPE -> (holder as CarouselViewHolder).bindData(courseListItemBy(adapterPosition = position)) + CAROUSEL_TYPE -> { + holder as CarouselViewHolder + val coursesCarouselInfo = courseListItemBy(adapterPosition = position) + val descriptionColors = getDescriptionColors(position) + holder.bindData(coursesCarouselInfo, descriptionColors) + } } } + private fun getDescriptionColors(position: Int): CollectionDescriptionColors = + when (position % 2) { + 0 -> CollectionDescriptionColors.BLUE + 1 -> CollectionDescriptionColors.FIRE + else -> throw IllegalStateException("Use correct divider") + } + private fun courseListItemBy(adapterPosition: Int): CoursesCarouselInfo = courseListItems[adapterPosition] override fun getItemCount(): Int = courseListItems.size @@ -43,7 +56,8 @@ class CatalogAdapter( private val coursesCarousel = itemView.coursesCarouselItem - fun bindData(coursesCarouselInfo: CoursesCarouselInfo) { + fun bindData(coursesCarouselInfo: CoursesCarouselInfo, descriptionColors: CollectionDescriptionColors) { + coursesCarousel.setDescriptionColors(descriptionColors) coursesCarousel.setCourseCarouselInfo(coursesCarouselInfo) } diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index c4920c6a37..e83650aace 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -27,6 +27,7 @@ import org.stepic.droid.core.presenters.PersistentCourseListPresenter import org.stepic.droid.core.presenters.contracts.ContinueCourseView import org.stepic.droid.core.presenters.contracts.CoursesView import org.stepic.droid.core.presenters.contracts.DroppingView +import org.stepic.droid.model.CollectionDescriptionColors import org.stepic.droid.model.Course import org.stepic.droid.model.CoursesCarouselInfo import org.stepic.droid.model.Section @@ -41,7 +42,6 @@ import org.stepic.droid.util.ColorUtil import org.stepic.droid.util.ProgressHelper import org.stepic.droid.util.StepikUtil import org.stepic.droid.util.SuppressFBWarnings -import timber.log.Timber import javax.inject.Inject @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "Kotlin adds null check for lateinit properties, but Findbugs highlights it as redundant") @@ -193,11 +193,21 @@ constructor( coursesCarouselTitle.setTextColor(ColorUtil.getColorArgb(info.colorType.textColor)) coursesCarouselRoot.setBackgroundColor(ColorUtil.getColorArgb(info.colorType.backgroundColorRes)) coursesViewAll.setTextColor(ColorUtil.getColorArgb(info.colorType.viewAllColorRes, context)) + showDescription(info.description) val showMore = info.table == Table.enrolled coursesRecycler.adapter = CoursesAdapter(context as FragmentActivity, courses, continueCoursePresenter, droppingPresenter, false, showMore, info.colorType) } + private fun showDescription(description: String) { + if (description.isNotBlank()) { + coursesCarouselDescription.setPlaceholderText(description) + coursesCarouselDescription.visibility = View.VISIBLE + } else { + coursesCarouselDescription.visibility = View.GONE + } + } + override fun onOpenStep(courseId: Long, section: Section, lessonId: Long, unitId: Long, stepPosition: Int) { ProgressHelper.dismiss(fragmentManager, continueLoadingTag) screenManager.continueCourse(activity, courseId, section, lessonId, unitId, stepPosition.toLong()) @@ -271,6 +281,7 @@ constructor( coursesRecycler.scrollToPosition(lastSavedScrollPosition) lastSavedScrollPosition = DEFAULT_SCROLL_POSITION } + showDescription(info.description) coursesRecycler.visibility = View.VISIBLE coursesViewAll.visibility = View.VISIBLE this.courses.clear() @@ -283,6 +294,7 @@ constructor( coursesViewAll.visibility = View.GONE coursesLoadingView.visibility = View.GONE coursesRecycler.visibility = View.GONE + coursesCarouselDescription.visibility = View.GONE coursesPlaceholder.setPlaceholderText(stringRes) coursesPlaceholder.setOnClickListener(listener) coursesPlaceholder.visibility = View.VISIBLE @@ -403,7 +415,6 @@ constructor( savedState.info = this._info savedState.scrollPosition = (coursesRecycler.layoutManager as GridLayoutManager).findFirstCompletelyVisibleItemPosition() - Timber.d("onSave ${savedState.scrollPosition}") return savedState } @@ -447,5 +458,9 @@ constructor( } } + fun setDescriptionColors(collectionDescriptionColors: CollectionDescriptionColors) { + coursesCarouselDescription.setBackgroundResource(collectionDescriptionColors.backgroundRes) + coursesCarouselDescription.setTextColor(ColorUtil.getColorArgb(collectionDescriptionColors.textColorRes, context)) + } } diff --git a/app/src/main/res/drawable/gradient_background_blue.xml b/app/src/main/res/drawable/gradient_background_blue.xml index f84e40e0d6..6f18d9a243 100644 --- a/app/src/main/res/drawable/gradient_background_blue.xml +++ b/app/src/main/res/drawable/gradient_background_blue.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> diff --git a/app/src/main/res/drawable/gradient_background_fire.xml b/app/src/main/res/drawable/gradient_background_fire.xml index 15d892be68..d1324d9127 100644 --- a/app/src/main/res/drawable/gradient_background_fire.xml +++ b/app/src/main/res/drawable/gradient_background_fire.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> #6969A0 @color/white - #D7E1E7 - #E1E8EF - - #D4D0D9 - #EDDFEB - #F5DEDC + #D3E4EC + #CFE8F5 + #00484E + + #E8E0F3 + #EFDFE7 + #F5DEDD + #18073D #F6F7F9 #DBDBDB diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml index 4c91361b2d..44f7caa931 100644 --- a/app/src/main/res/values/integers.xml +++ b/app/src/main/res/values/integers.xml @@ -7,4 +7,5 @@ 128 300 4 + 45 \ No newline at end of file From 5cfa06cfe9d11849970db97678ceffde91843deb Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 13:03:53 +0300 Subject: [PATCH 040/140] add extra space between course collections --- app/src/main/res/layout/fragment_courses_carousel.xml | 2 ++ app/src/main/res/values/dimens.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/app/src/main/res/layout/fragment_courses_carousel.xml b/app/src/main/res/layout/fragment_courses_carousel.xml index 7146c949ce..83f67feaa2 100644 --- a/app/src/main/res/layout/fragment_courses_carousel.xml +++ b/app/src/main/res/layout/fragment_courses_carousel.xml @@ -96,6 +96,7 @@ android:scrollbars="none" android:splitMotionEvents="false" android:visibility="gone" + android:layout_marginBottom="@dimen/course_list_bottom_padding" /> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 655dc7011c..b7f31301e9 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -109,6 +109,7 @@ 20dp 12dp 30dp + 14dp 8dp @dimen/course_widget_radius 140dp From 833364dfc2d8c3e0d0bc185496eb0a15e4191ffe Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 13:05:15 +0300 Subject: [PATCH 041/140] rename courses carousel (fragment->view) --- .../java/org/stepic/droid/ui/custom/CoursesCarouselView.kt | 4 ++-- ...ragment_courses_carousel.xml => view_courses_carousel.xml} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename app/src/main/res/layout/{fragment_courses_carousel.xml => view_courses_carousel.xml} (100%) diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index e83650aace..45785f7ece 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -12,7 +12,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.FrameLayout import android.widget.Toast -import kotlinx.android.synthetic.main.fragment_courses_carousel.view.* +import kotlinx.android.synthetic.main.view_courses_carousel.view.* import org.stepic.droid.R import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App @@ -123,7 +123,7 @@ constructor( .inject(this) val layoutInflater = LayoutInflater.from(context) - layoutInflater.inflate(R.layout.fragment_courses_carousel, this, true) + layoutInflater.inflate(R.layout.view_courses_carousel, this, true) initCourseCarousel() } diff --git a/app/src/main/res/layout/fragment_courses_carousel.xml b/app/src/main/res/layout/view_courses_carousel.xml similarity index 100% rename from app/src/main/res/layout/fragment_courses_carousel.xml rename to app/src/main/res/layout/view_courses_carousel.xml From d11a0865c7cca35700760bdcb315b865d9978bcd Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 13:09:25 +0300 Subject: [PATCH 042/140] change course carousel top padding for title --- app/src/main/res/values/dimens.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index b7f31301e9..ec1ee2d6c8 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -115,7 +115,7 @@ 140dp 33dp 20sp - 24dp + 20dp 0dp From b6c13ca75c795f6f04054b409055a9421c52b21b Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Wed, 8 Nov 2017 14:39:03 +0300 Subject: [PATCH 043/140] search suggestions [draft] --- .../droid/ui/adapters/SearchQueriesAdapter.kt | 59 +++++++++++++++++++ .../droid/ui/fragments/FindCoursesFragment.kt | 59 +++++++++++++++---- 2 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/ui/adapters/SearchQueriesAdapter.kt diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/SearchQueriesAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/SearchQueriesAdapter.kt new file mode 100644 index 0000000000..deb4d70659 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/adapters/SearchQueriesAdapter.kt @@ -0,0 +1,59 @@ +package org.stepic.droid.ui.adapters + +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.SearchView +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.search_query_item.view.* +import org.stepic.droid.R +import org.stepic.droid.model.SearchQuery + + +class SearchQueriesAdapter : RecyclerView.Adapter() { + private var items: List = emptyList() + private var rawItems: List = emptyList() + var constraint: String = "" + set(value) { + field = value + filterItems() + } + + var searchView: SearchView? = null + + override fun onBindViewHolder(holder: SearchQueryViewHolder, p: Int) { + val query = items[p] + val spannable = SpannableString(query.text) + + val spanStart = query.text.indexOf(constraint, ignoreCase = true) + if (spanStart != -1) { + spannable.setSpan(ForegroundColorSpan(0x44000000), spanStart, spanStart + constraint.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + + holder.itemView.searchQuery.text = spannable + holder.itemView.setOnClickListener { + searchView?.setQuery(query.text, true) + } + } + + fun replace(collection: List) { + rawItems = collection + filterItems() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + SearchQueryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.search_query_item, parent, false)) + + + override fun getItemCount() = items.size + + private fun filterItems() { + items = rawItems.filter { it.text.contains(constraint, ignoreCase = true) } + notifyDataSetChanged() + } + + class SearchQueryViewHolder(view: View) : RecyclerView.ViewHolder(view) +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt index b00be539a0..40274779c2 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.kt @@ -5,15 +5,19 @@ import android.content.Context import android.os.Bundle import android.support.annotation.StringRes import android.support.v4.content.ContextCompat +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView import android.support.v7.widget.SearchView -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.widget.ImageView +import android.util.Log +import android.view.* +import android.widget.* +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import kotlinx.android.synthetic.main.search_queries_recycler_view.view.* import org.stepic.droid.R import org.stepic.droid.base.CoursesDatabaseFragmentBase import org.stepic.droid.storage.operations.Table +import org.stepic.droid.ui.adapters.SearchQueriesAdapter import org.stepic.droid.ui.util.initCenteredToolbar import org.stepic.droid.util.liftM2 @@ -22,15 +26,17 @@ open class FindCoursesFragment: CoursesDatabaseFragmentBase() { fun newInstance() = FindCoursesFragment() } + private var mAdapter: SearchQueriesAdapter? = null + private lateinit var searchQueriesRecyclerView: RecyclerView + private var searchView: SearchView? = null - private var menuItem: MenuItem? = null + private var searchMenuItem: MenuItem? = null private var handledByRoot = false override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { setHasOptionsMenu(true) super.onViewCreated(view, savedInstanceState) initCenteredToolbar(getTitle(), false) - rootView.setParentTouchEvent { collapseAndHide(true) } listOfCoursesView.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus -> if (hasFocus) { @@ -41,19 +47,36 @@ open class FindCoursesFragment: CoursesDatabaseFragmentBase() { } } + mAdapter = SearchQueriesAdapter() + searchQueriesRecyclerView = layoutInflater.inflate(R.layout.search_queries_recycler_view, rootView, false).searchQueriesRecyclerView + searchQueriesRecyclerView.layoutManager = LinearLayoutManager(context) + searchQueriesRecyclerView.adapter = mAdapter + searchQueriesRecyclerView.setOnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + collapseAndHide(false) + } else { + hideSoftKeypad() // such compromise to avoid using adjustResize on parent activity + } + false + } + + + rootView.addView(searchQueriesRecyclerView) } override fun onDestroyView() { listOfCoursesView.onFocusChangeListener = null + mAdapter = null super.onDestroyView() } private fun collapseAndHide(rootHandle: Boolean) { - searchView.liftM2(menuItem) { _, menuItem -> + searchView.liftM2(searchMenuItem) { _, menuItem -> if (menuItem.isActionViewExpanded) { if (rootHandle) handledByRoot = true hideSoftKeypad() menuItem.collapseActionView() + searchQueriesRecyclerView.visibility = View.GONE } } } @@ -65,9 +88,9 @@ open class FindCoursesFragment: CoursesDatabaseFragmentBase() { super.onCreateOptionsMenu(menu, inflater) val searchManager = activity.getSystemService(Context.SEARCH_SERVICE) as SearchManager - menuItem = menu.findItem(R.id.action_search) + searchMenuItem = menu.findItem(R.id.action_search) - searchView = menuItem?.actionView as SearchView + searchView = searchMenuItem?.actionView as? SearchView searchView?.let { val closeImageView: ImageView = it.findViewById(R.id.search_close_btn) closeImageView.setImageDrawable(ContextCompat.getDrawable(context, getCloseIconDrawableRes())) @@ -83,9 +106,17 @@ open class FindCoursesFragment: CoursesDatabaseFragmentBase() { } override fun onQueryTextChange(newText: String): Boolean { + populateAdapter(newText) return false } }) + + it.setOnSearchClickListener { + searchQueriesRecyclerView.scrollTo(0, 0) + searchQueriesRecyclerView.visibility = View.VISIBLE + } + + mAdapter?.searchView = it } } @@ -99,4 +130,12 @@ open class FindCoursesFragment: CoursesDatabaseFragmentBase() { @StringRes protected open fun getTitle() = R.string.catalog_title + + private fun populateAdapter(query: String) { + mAdapter?.constraint = query + api.getSearchQueries(query).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe({ + Log.d(javaClass.canonicalName, it.toString()) + mAdapter?.replace(it.queries) + }, { it.printStackTrace() }) + } } \ No newline at end of file From ca2be900c03f2c6d93d6158f43de9be5622ddb79 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 14:50:57 +0300 Subject: [PATCH 044/140] add search to catalog --- .../CourseSearchResultActivity.java | 11 +-- .../droid/ui/fragments/CatalogFragment.kt | 48 +++++++++++- .../ui/fragments/FindCoursesFragment.java | 74 +------------------ .../org/stepic/droid/ui/util/SearchHelper.kt | 33 +++++++++ app/src/main/res/layout/fragment_catalog.xml | 3 + 5 files changed, 84 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/ui/util/SearchHelper.kt diff --git a/app/src/main/java/org/stepic/droid/ui/activities/CourseSearchResultActivity.java b/app/src/main/java/org/stepic/droid/ui/activities/CourseSearchResultActivity.java index f377d63aaf..5a78e30cd1 100644 --- a/app/src/main/java/org/stepic/droid/ui/activities/CourseSearchResultActivity.java +++ b/app/src/main/java/org/stepic/droid/ui/activities/CourseSearchResultActivity.java @@ -24,13 +24,9 @@ public class CourseSearchResultActivity extends FragmentActivityBase { - private final static String TAG = "SearchActivity"; - @BindView(R.id.frame) View rootFrame; - private MenuItem menuItem; - private SearchView searchView; private String query; @Override @@ -88,15 +84,12 @@ public boolean onOptionsItemSelected(MenuItem item) { public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.search_menu, menu); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); - menuItem = menu.findItem(R.id.action_search); - searchView = (SearchView) menuItem.getActionView(); + MenuItem menuItem = menu.findItem(R.id.action_search); + SearchView searchView = (SearchView) menuItem.getActionView(); ImageView closeImageView = searchView.findViewById(R.id.search_close_btn); closeImageView.setImageDrawable(ContextCompat.getDrawable(this, getCloseIconDrawableRes())); - ImageView searchButtonImageView = searchView.findViewById(R.id.search_button); - searchButtonImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_comment_black_24dp)); - ComponentName componentName = getComponentName(); SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName); searchView.setSearchableInfo(searchableInfo); diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt index e16852b0a0..494a5b3bb2 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -2,9 +2,8 @@ package org.stepic.droid.ui.fragments import android.os.Bundle import android.support.v7.widget.LinearLayoutManager -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.support.v7.widget.SearchView +import android.view.* import kotlinx.android.synthetic.main.fragment_catalog.* import org.stepic.droid.R import org.stepic.droid.base.App @@ -13,6 +12,7 @@ import org.stepic.droid.core.presenters.CatalogPresenter import org.stepic.droid.core.presenters.contracts.CatalogView import org.stepic.droid.model.CoursesCarouselInfo import org.stepic.droid.ui.adapters.CatalogAdapter +import org.stepic.droid.ui.util.SearchHelper import org.stepic.droid.ui.util.initCenteredToolbar import javax.inject.Inject @@ -28,6 +28,13 @@ class CatalogFragment : FragmentBase(), private val courseCarouselInfoList = mutableListOf() + private var searchMenuItem: MenuItem? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + } + override fun injectComponent() { App .Companion @@ -43,6 +50,11 @@ class CatalogFragment : FragmentBase(), override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + catalogRecyclerView.setOnFocusChangeListener { v, hasFocus -> + if (hasFocus) { + collapseAndHide() + } + } initCenteredToolbar(R.string.catalog_title, showHomeButton = false) initMainRecycler() @@ -71,4 +83,34 @@ class CatalogFragment : FragmentBase(), //do nothing } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + searchMenuItem = SearchHelper.createSearch(menu, inflater, activity) + (searchMenuItem?.actionView as SearchView).setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextChange(newText: String?): Boolean = false + + override fun onQueryTextSubmit(query: String?): Boolean { + collapseAndHide() + return false + } + + }) + } + + + override fun onDestroyOptionsMenu() { + super.onDestroyOptionsMenu() + + (searchMenuItem?.actionView as? SearchView)?.setOnQueryTextListener(null) + searchMenuItem = null + } + + private fun collapseAndHide() { + if (searchMenuItem?.isActionViewExpanded == true) { + hideSoftKeypad() + searchMenuItem?.collapseActionView() + } + } + + } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java index a1567e0249..a306b9a8e0 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java @@ -1,18 +1,8 @@ package org.stepic.droid.ui.fragments; -import android.app.SearchManager; -import android.app.SearchableInfo; -import android.content.ComponentName; -import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.SearchView; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; -import android.widget.ImageView; import org.stepic.droid.R; import org.stepic.droid.base.CoursesDatabaseFragmentBase; @@ -26,10 +16,6 @@ public static FindCoursesFragment newInstance() { return new FindCoursesFragment(); } - private SearchView searchView = null; - private MenuItem menuItem = null; - private boolean handledByRoot = false; - @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { setHasOptionsMenu(true); @@ -41,19 +27,6 @@ public void makeBeforeChildren() { collapseAndHide(true); } }); - - listOfCoursesView.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - if (!handledByRoot) { - collapseAndHide(false); - } - handledByRoot = false; - } - } - }); - } @Override @@ -65,11 +38,6 @@ public void onDestroyView() { } private void collapseAndHide(boolean rootHandle) { - if (searchView != null && menuItem != null && menuItem.isActionViewExpanded()) { - if (rootHandle) handledByRoot = true; - hideSoftKeypad();//in collapse action view keypad going to invisible after animation - menuItem.collapseActionView(); - } } @Override @@ -77,47 +45,7 @@ protected Table getCourseType() { return Table.featured; } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.search_menu, menu); - super.onCreateOptionsMenu(menu, inflater); - - SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); - menuItem = menu.findItem(R.id.action_search); - searchView = (SearchView) menuItem.getActionView(); - - ImageView closeImageView = searchView.findViewById(R.id.search_close_btn); - closeImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), getCloseIconDrawableRes())); - - ComponentName componentName = getActivity().getComponentName(); - SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName); - searchView.setSearchableInfo(searchableInfo); - searchView.setMaxWidth(20000);//it is dirty workaround for expand in landscape - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - collapseAndHide(false); - return false; - } - - @Override - public boolean onQueryTextChange(String newText) { - return false; - } - }); - } - - @Override - public void onDestroyOptionsMenu() { - super.onDestroyOptionsMenu(); - - if (searchView != null) { - searchView.setOnQueryTextListener(null); - } - searchView = null; - } - - protected String getTitle () { + protected String getTitle() { return getString(R.string.catalog_title); } } diff --git a/app/src/main/java/org/stepic/droid/ui/util/SearchHelper.kt b/app/src/main/java/org/stepic/droid/ui/util/SearchHelper.kt new file mode 100644 index 0000000000..8f0a742203 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/ui/util/SearchHelper.kt @@ -0,0 +1,33 @@ +package org.stepic.droid.ui.util + +import android.app.Activity +import android.app.SearchManager +import android.content.Context +import android.support.v4.content.ContextCompat +import android.support.v7.widget.SearchView +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.widget.ImageView +import org.stepic.droid.R +import org.stepic.droid.ui.util.CloseIconHolder.getCloseIconDrawableRes + +object SearchHelper { + fun createSearch(menu: Menu, inflater: MenuInflater, activity: Activity): MenuItem { + inflater.inflate(R.menu.search_menu, menu) + val searchManager = activity.getSystemService(Context.SEARCH_SERVICE) as SearchManager + + val menuItem = menu.findItem(R.id.action_search) + val searchView = menuItem.actionView as SearchView + + val closeImageView = searchView.findViewById(R.id.search_close_btn) + closeImageView.setImageDrawable(ContextCompat.getDrawable(activity, getCloseIconDrawableRes())) + + val componentName = activity.componentName + val searchableInfo = searchManager.getSearchableInfo(componentName) + searchView.setSearchableInfo(searchableInfo) + searchView.maxWidth = 20000//it is dirty workaround for expand in landscape + + return menuItem + } +} diff --git a/app/src/main/res/layout/fragment_catalog.xml b/app/src/main/res/layout/fragment_catalog.xml index 012618a57e..c71cc0ed41 100644 --- a/app/src/main/res/layout/fragment_catalog.xml +++ b/app/src/main/res/layout/fragment_catalog.xml @@ -17,7 +17,10 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:descendantFocusability="beforeDescendants" android:divider="@color/transparent" + android:focusable="true" + android:focusableInTouchMode="true" android:overScrollMode="never" android:scrollbarStyle="outsideOverlay" android:scrollbars="none" From 89a094f684d1f0895bc103fe6304c4b3845542b8 Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 14:51:57 +0300 Subject: [PATCH 045/140] change to '_' unused name in lambda --- .../main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt index 494a5b3bb2..22f8a1ebe2 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/CatalogFragment.kt @@ -50,7 +50,7 @@ class CatalogFragment : FragmentBase(), override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - catalogRecyclerView.setOnFocusChangeListener { v, hasFocus -> + catalogRecyclerView.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) { collapseAndHide() } From 09791d8d1e2547c761e805e14c5f53eecd2aa90a Mon Sep 17 00:00:00 2001 From: Kirill Makarov Date: Wed, 8 Nov 2017 15:52:27 +0300 Subject: [PATCH 046/140] remove visual filters from app. Now shared preferences depend on default filters. Default filters are used, if user doesn't set filters before. We will show language filters at catalog in future. So, when user click 1st time on language filter in catalog, default filters won't be used --- app/src/main/AndroidManifest.xml | 10 -- .../org/stepic/droid/analytic/Analytic.java | 5 - .../base/CoursesDatabaseFragmentBase.java | 94 ++-------- .../droid/base/FragmentActivityBase.java | 4 - .../org/stepic/droid/core/DefaultFilter.java | 11 -- .../org/stepic/droid/core/DefaultFilter.kt | 8 + .../stepic/droid/core/DefaultFilterImpl.kt | 47 +---- .../stepic/droid/core/FilterApplicator.java | 5 +- .../stepic/droid/core/FilterApplicatorImpl.kt | 69 ++------ .../org/stepic/droid/core/ScreenManager.java | 2 - .../stepic/droid/core/ScreenManagerImpl.java | 15 -- .../PersistentCourseListPresenter.kt | 41 ++--- .../droid/di/filters/FilterComponent.kt | 2 - .../org/stepic/droid/model/StepikFilter.java | 2 +- .../preferences/SharedPreferenceHelper.java | 90 ++++------ .../droid/ui/activities/FilterActivity.kt | 29 --- .../droid/ui/activities/SplashActivity.java | 2 +- .../droid/ui/custom/CoursesCarouselView.kt | 2 +- .../ui/fragments/FastContinueFragment.kt | 8 +- .../droid/ui/fragments/FilterFragment.kt | 152 ---------------- .../ui/fragments/FindCoursesFragment.java | 51 ------ .../droid/ui/fragments/MyCoursesFragment.kt | 6 +- .../fragments/PopularCoursesAloneFragment.kt | 20 ++- .../main/res/drawable-hdpi/ic_action_tune.png | Bin 440 -> 0 bytes .../main/res/drawable-mdpi/ic_action_tune.png | Bin 255 -> 0 bytes .../res/drawable-xhdpi/ic_action_tune.png | Bin 390 -> 0 bytes .../res/drawable-xxhdpi/ic_action_tune.png | Bin 522 -> 0 bytes .../res/drawable-xxxhdpi/ic_action_tune.png | Bin 796 -> 0 bytes app/src/main/res/layout/fragment_filter.xml | 166 ------------------ app/src/main/res/menu/filter_courses_menu.xml | 9 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values/strings.xml | 1 - 32 files changed, 121 insertions(+), 731 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/core/DefaultFilter.java create mode 100644 app/src/main/java/org/stepic/droid/core/DefaultFilter.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/activities/FilterActivity.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/FilterFragment.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java delete mode 100644 app/src/main/res/drawable-hdpi/ic_action_tune.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_action_tune.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_action_tune.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_tune.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_tune.png delete mode 100644 app/src/main/res/layout/fragment_filter.xml delete mode 100644 app/src/main/res/menu/filter_courses_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cbbee546b3..3f37e93217 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -248,16 +248,6 @@ android:value=".ui.activities.CommentsActivity"/> - - - - - diff --git a/app/src/main/java/org/stepic/droid/analytic/Analytic.java b/app/src/main/java/org/stepic/droid/analytic/Analytic.java index ac08f52aed..7ff99ee55b 100644 --- a/app/src/main/java/org/stepic/droid/analytic/Analytic.java +++ b/app/src/main/java/org/stepic/droid/analytic/Analytic.java @@ -386,11 +386,6 @@ interface Certificate { String OPEN_CERTIFICATE_FROM_NOTIFICATION_CENTER = "certificate_notification_center"; } - interface Filters { - String FILTERS_CANCELED = "filters_canceled"; - String FILTERS_NEED_UPDATE = "filters_need_update"; - } - interface Exam { String START_EXAM = "exam_start"; String SHOW_EXAM = "exam_shown_on_bind_view"; diff --git a/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java b/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java index 8441f7ab86..f34443d6a6 100644 --- a/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java +++ b/app/src/main/java/org/stepic/droid/base/CoursesDatabaseFragmentBase.java @@ -1,13 +1,10 @@ package org.stepic.droid.base; -import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.view.ContextMenu; -import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; @@ -22,9 +19,7 @@ import org.stepic.droid.model.Course; import org.stepic.droid.storage.operations.Table; import org.stepic.droid.ui.fragments.CourseListFragmentBase; -import org.stepic.droid.ui.util.BackButtonHandler; import org.stepic.droid.ui.util.ContextMenuRecyclerView; -import org.stepic.droid.ui.util.OnBackClickListener; import org.stepic.droid.util.AppConstants; import org.stepic.droid.util.ContextMenuCourseUtil; @@ -32,31 +27,15 @@ import javax.inject.Inject; -public abstract class CoursesDatabaseFragmentBase extends CourseListFragmentBase implements FilterForCoursesView, OnBackClickListener, DroppingListener { - private static final int FILTER_REQUEST_CODE = 776; - - private boolean needFilter = false; - +public abstract class CoursesDatabaseFragmentBase extends CourseListFragmentBase implements FilterForCoursesView, DroppingListener { @Inject PersistentCourseListPresenter courseListPresenter; @Inject Client droppingClient; - private BackButtonHandler backButtonHandler = null; private boolean isScreenCreated; - @Override - public void onAttach(Context context) { - super.onAttach(context); - - Activity rootActivity = getActivity(); - if (rootActivity != null && rootActivity instanceof BackButtonHandler) { - backButtonHandler = ((BackButtonHandler) rootActivity); - backButtonHandler.setBackClickListener(this); - } - } - @Override protected void injectComponent() { App.Companion @@ -76,22 +55,6 @@ public void onCreate(Bundle savedInstanceState) { isScreenCreated = true; } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.filter_courses_menu, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_filter_menu: - getScreenManager().showFilterScreen(this, FILTER_REQUEST_CODE, getCourseType()); - return true; - } - - return super.onOptionsItemSelected(item); - } - @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { nullifyActivityBackground(); @@ -107,12 +70,11 @@ public void onStart() { if (isScreenCreated) { //reset all data isScreenCreated = false; - needFilter = false; courses.clear(); - courseListPresenter.refreshData(getCourseType(), needFilter, true); + courseListPresenter.refreshData(getCourseType(), true); } else { //load if not - courseListPresenter.downloadData(getCourseType(), needFilter); + courseListPresenter.downloadData(getCourseType()); } swipeRefreshLayout.setRefreshing(false); } @@ -175,27 +137,11 @@ private void showInfo(int position) { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (resultCode == FragmentActivity.RESULT_OK) { - if (requestCode == AppConstants.REQUEST_CODE_DETAIL) { - Course course = data.getParcelableExtra(AppConstants.COURSE_ID_KEY); - int enrollment = data.getIntExtra(AppConstants.ENROLLMENT_KEY, 0); - if (course != null && enrollment != 0) { - updateEnrollment(course, enrollment); - } - } - - if (requestCode == FILTER_REQUEST_CODE) { - getAnalytic().reportEvent(Analytic.Filters.FILTERS_NEED_UPDATE); - needFilter = true; // not last filter? check it - courses.clear(); - coursesAdapter.notifyDataSetChanged(); - courseListPresenter.refreshData(getCourseType(), needFilter, true); - } - } - - if (resultCode == FragmentActivity.RESULT_CANCELED) { - if (requestCode == FILTER_REQUEST_CODE) { - getAnalytic().reportEvent(Analytic.Filters.FILTERS_CANCELED); + if (resultCode == FragmentActivity.RESULT_OK && requestCode == AppConstants.REQUEST_CODE_DETAIL) { + Course course = data.getParcelableExtra(AppConstants.COURSE_ID_KEY); + int enrollment = data.getIntExtra(AppConstants.ENROLLMENT_KEY, 0); + if (course != null && enrollment != 0) { + updateEnrollment(course, enrollment); } } } @@ -232,7 +178,7 @@ public void showEmptyScreen(boolean isShown) { @Override public void onNeedDownloadNextPage() { - courseListPresenter.loadMore(getCourseType(), needFilter); + courseListPresenter.loadMore(getCourseType()); } @Override @@ -250,22 +196,7 @@ public void showFilteredCourses(@NotNull List filteredList) { @Override public void onRefresh() { getAnalytic().reportEvent(Analytic.Interaction.PULL_TO_REFRESH_COURSE); - courseListPresenter.refreshData(getCourseType(), needFilter, true); - } - - @Override - public boolean onBackClick() { - getSharedPreferenceHelper().onTryDiscardFilters(getCourseType()); - return false; - } - - @Override - public void onDetach() { - if (backButtonHandler != null) { - backButtonHandler.removeBackClickListener(this); - backButtonHandler = null; - } - super.onDetach(); + courseListPresenter.refreshData(getCourseType(), true); } @Override @@ -303,4 +234,9 @@ public void onSuccessDropCourse(@NotNull Course droppedCourse) { showEmptyScreen(true); } } + + + @NotNull + @Override + protected abstract Table getCourseType(); } diff --git a/app/src/main/java/org/stepic/droid/base/FragmentActivityBase.java b/app/src/main/java/org/stepic/droid/base/FragmentActivityBase.java index f2f8a2789e..615acafbd0 100644 --- a/app/src/main/java/org/stepic/droid/base/FragmentActivityBase.java +++ b/app/src/main/java/org/stepic/droid/base/FragmentActivityBase.java @@ -20,7 +20,6 @@ import org.stepic.droid.analytic.Analytic; import org.stepic.droid.concurrency.MainHandler; import org.stepic.droid.configuration.Config; -import org.stepic.droid.core.DefaultFilter; import org.stepic.droid.core.ScreenManager; import org.stepic.droid.core.ShareHelper; import org.stepic.droid.fonts.FontsProvider; @@ -61,9 +60,6 @@ public abstract class FragmentActivityBase extends AppCompatActivity { @Inject protected ShareHelper shareHelper; - @Inject - protected DefaultFilter defaultFilter; - @Inject protected Config config; diff --git a/app/src/main/java/org/stepic/droid/core/DefaultFilter.java b/app/src/main/java/org/stepic/droid/core/DefaultFilter.java deleted file mode 100644 index 563b384fb5..0000000000 --- a/app/src/main/java/org/stepic/droid/core/DefaultFilter.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.stepic.droid.core; - -import org.stepic.droid.model.StepikFilter; - -public interface DefaultFilter { - boolean getDefaultFeatured(StepikFilter filterValue); - - boolean getDefaultEnrolled(StepikFilter filterValue); - - void setNeedResolveLanguage(); -} diff --git a/app/src/main/java/org/stepic/droid/core/DefaultFilter.kt b/app/src/main/java/org/stepic/droid/core/DefaultFilter.kt new file mode 100644 index 0000000000..39e3a31e6c --- /dev/null +++ b/app/src/main/java/org/stepic/droid/core/DefaultFilter.kt @@ -0,0 +1,8 @@ +package org.stepic.droid.core + +import org.stepic.droid.model.StepikFilter + +interface DefaultFilter { + + fun getDefaultFilter(filterValue: StepikFilter, needResolveLanguage: Boolean): Boolean +} diff --git a/app/src/main/java/org/stepic/droid/core/DefaultFilterImpl.kt b/app/src/main/java/org/stepic/droid/core/DefaultFilterImpl.kt index 48409c361e..b7f465800f 100644 --- a/app/src/main/java/org/stepic/droid/core/DefaultFilterImpl.kt +++ b/app/src/main/java/org/stepic/droid/core/DefaultFilterImpl.kt @@ -3,45 +3,29 @@ package org.stepic.droid.core import android.content.Context import android.os.Build import org.stepic.droid.model.StepikFilter -import org.stepic.droid.preferences.SharedPreferenceHelper import java.util.* import javax.inject.Inject class DefaultFilterImpl -@Inject constructor(private val context: Context) : DefaultFilter { +@Inject +constructor(private val context: Context) : DefaultFilter { private var isNeedRussian: Boolean? = null - private val SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING = "before116" - override fun getDefaultFeatured(filterValue: StepikFilter): Boolean = + override fun getDefaultFilter(filterValue: StepikFilter, needResolveLanguage: Boolean): Boolean = when (filterValue) { - StepikFilter.RUSSIAN -> isNeedRussian() + StepikFilter.RUSSIAN -> isNeedRussian(needResolveLanguage) StepikFilter.ENGLISH -> true - StepikFilter.UPCOMING -> true - StepikFilter.ACTIVE -> true - StepikFilter.PAST -> true - StepikFilter.PERSISTENT -> false } - override fun getDefaultEnrolled(filterValue: StepikFilter): Boolean = - //my courses is persistent by default - when (filterValue) { - StepikFilter.RUSSIAN -> true - StepikFilter.ENGLISH -> true - StepikFilter.UPCOMING -> true - StepikFilter.ACTIVE -> true - StepikFilter.PAST -> true - StepikFilter.PERSISTENT -> true - } - - private fun isNeedRussian(): Boolean { + private fun isNeedRussian(needResolveLanguage: Boolean): Boolean { val isNeedRussianNotNull = isNeedRussian ?: false if (isNeedRussian != null) { return isNeedRussianNotNull // do not change on language change, it is just helper for not russian speaker, choose performance. } - if (!needResolveLanguage()) { + if (!needResolveLanguage) { val isNeedRussianLocal = true isNeedRussian = isNeedRussianLocal return isNeedRussianLocal // show russian always for old users (before 1.16) @@ -59,23 +43,4 @@ class DefaultFilterImpl isNeedRussian = newValue return newValue } - - //avoid cyclic dependency - override fun setNeedResolveLanguage() { - put(SharedPreferenceHelper.PreferenceType.DEVICE_SPECIFIC, SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING, true) - } - - //avoid cyclic dependency - private fun needResolveLanguage(): Boolean = - getBoolean(SharedPreferenceHelper.PreferenceType.DEVICE_SPECIFIC, SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING, false) //by default user before 116 and we don't show he/she only language courses #Apps-430 - - //avoid cyclic dependency - private fun getBoolean(preferenceType: SharedPreferenceHelper.PreferenceType, key: String, defaultValue: Boolean): Boolean = - context.getSharedPreferences(preferenceType.storeName, Context.MODE_PRIVATE).getBoolean(key, defaultValue) - - //avoid cyclic dependency - private fun put(type: SharedPreferenceHelper.PreferenceType, key: String, value: Boolean?) { - val editor = context.getSharedPreferences(type.storeName, Context.MODE_PRIVATE).edit() - editor.putBoolean(key, value!!).apply() - } } \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/core/FilterApplicator.java b/app/src/main/java/org/stepic/droid/core/FilterApplicator.java index 460ed3a571..4e60783a0e 100644 --- a/app/src/main/java/org/stepic/droid/core/FilterApplicator.java +++ b/app/src/main/java/org/stepic/droid/core/FilterApplicator.java @@ -1,12 +1,9 @@ package org.stepic.droid.core; import org.stepic.droid.model.Course; -import org.stepic.droid.storage.operations.Table; import java.util.List; public interface FilterApplicator { - List getFilteredFeaturedFromSharedPrefs(List sourceCourses); - - List getFilteredFeaturedFromDefault(List sourceCourses); + List filterCourses(List sourceCourses); } diff --git a/app/src/main/java/org/stepic/droid/core/FilterApplicatorImpl.kt b/app/src/main/java/org/stepic/droid/core/FilterApplicatorImpl.kt index b79fd0f9a7..b759c624a8 100644 --- a/app/src/main/java/org/stepic/droid/core/FilterApplicatorImpl.kt +++ b/app/src/main/java/org/stepic/droid/core/FilterApplicatorImpl.kt @@ -3,73 +3,32 @@ package org.stepic.droid.core import org.stepic.droid.model.Course import org.stepic.droid.model.StepikFilter import org.stepic.droid.preferences.SharedPreferenceHelper -import org.stepic.droid.util.DateTimeHelper import javax.inject.Inject class FilterApplicatorImpl -@Inject constructor(private val defaultFilter: DefaultFilter, - private val sharedPreferenceHelper: SharedPreferenceHelper) : FilterApplicator { +@Inject constructor(private val sharedPreferenceHelper: SharedPreferenceHelper) : FilterApplicator { - override fun getFilteredFeaturedFromSharedPrefs(sourceCourses: List): List = + override fun filterCourses(sourceCourses: List): List = resolveFiltersForList(sourceCourses, sharedPreferenceHelper.filterForFeatured) - - override fun getFilteredFeaturedFromDefault(sourceCourses: List): List? { - val filters = StepikFilter.values().filter { defaultFilter.getDefaultFeatured(it) }.toSet() - return resolveFiltersForList(sourceCourses, filters) - } - private fun resolveFiltersForList(sourceCourses: List, filters: Set): List { - //local helper functions: - fun resolveFilters(course: Course, now: Long, applyFilters: (Course, endDate: Long?, isAfterBeginOrNotStartable: Boolean, isBeginDateInFuture: Boolean, isEndDateInFuture: Boolean, isEnded: Boolean, filterSet: Set) -> Boolean, filterSet: Set): Boolean { - val beginDate: Long? = course.beginDate?.let { - DateTimeHelper.toCalendar(it).timeInMillis - } - - val endDate: Long? = course.endDate?.let { - DateTimeHelper.toCalendar(it).timeInMillis - } - - val isEnded: Boolean = course.lastDeadline?.let { - val lastDeadlineMillis = DateTimeHelper.toCalendar(it).timeInMillis - now > lastDeadlineMillis - } ?: false - - val isBeginDateInFuture: Boolean = beginDate?.compareTo(now) ?: -1 > 0 - val isEndDateInFuture: Boolean = endDate?.compareTo(now) ?: -1 > 0 - - val isAfterBeginOrNotStartable = (beginDate != null && !isBeginDateInFuture || beginDate == null) - return applyFilters.invoke(course, endDate, isAfterBeginOrNotStartable, isBeginDateInFuture, isEndDateInFuture, isEnded, filterSet) - - } - - fun applyFiltersForSet(course: Course, endDate: Long?, isAfterBeginOrNotStartable: Boolean, isBeginDateInFuture: Boolean, isEndDateInFuture: Boolean, isEnded: Boolean, filters: Set): Boolean { - return ( - filters.contains(StepikFilter.RUSSIAN) && course.language?.equals("ru") ?: false - || filters.contains(StepikFilter.ENGLISH) && course.language?.equals("en") ?: false - || (filters.contains(StepikFilter.RUSSIAN) && filters.contains(StepikFilter.ENGLISH)) - ) - - && - (filters.contains(StepikFilter.UPCOMING) && isBeginDateInFuture - || filters.contains(StepikFilter.ACTIVE) && (!isEnded && isAfterBeginOrNotStartable || endDate != null && isEndDateInFuture && !isBeginDateInFuture) - || filters.contains(StepikFilter.PAST) && (endDate == null && isEnded || endDate != null && !isEndDateInFuture)) - } - - //logic - - val possibleFilterSize = StepikFilter.values().size - if (possibleFilterSize == filters.size - || possibleFilterSize - 1 == filters.size && !filters.contains(StepikFilter.PERSISTENT)) { + if (StepikFilter.values().size == filters.size) { // if all filters are chosen or all except persistent is chosen -> do not filter return sourceCourses } - val now: Long = DateTimeHelper.nowUtc() - val filteredList = sourceCourses.filter { course -> - resolveFilters(course, now, ::applyFiltersForSet, filters) + return sourceCourses.filter { course -> + applyFiltersForSet(course, filters) } - return filteredList + } + + private fun applyFiltersForSet(course: Course, filters: Set): Boolean { + return ( + filters.contains(StepikFilter.RUSSIAN) && course.language?.equals("ru") ?: false + || filters.contains(StepikFilter.ENGLISH) && course.language?.equals("en") ?: false + || (filters.contains(StepikFilter.RUSSIAN) && filters.contains(StepikFilter.ENGLISH) + || (!filters.contains(StepikFilter.RUSSIAN) && !filters.contains(StepikFilter.ENGLISH))) + ) } } diff --git a/app/src/main/java/org/stepic/droid/core/ScreenManager.java b/app/src/main/java/org/stepic/droid/core/ScreenManager.java index 2c4e149d0e..64de6c55f7 100644 --- a/app/src/main/java/org/stepic/droid/core/ScreenManager.java +++ b/app/src/main/java/org/stepic/droid/core/ScreenManager.java @@ -93,8 +93,6 @@ public interface ScreenManager { void addCertificateToLinkedIn(CertificateViewItem certificateViewItem); - void showFilterScreen(Fragment sourceFragment, int requestCode, Table courseType); - void showCertificates(Context context); void openSyllabusInWeb(Context context, long courseId); diff --git a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java index 606cd0faf5..9706c3632c 100644 --- a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java +++ b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java @@ -33,7 +33,6 @@ import org.stepic.droid.preferences.SharedPreferenceHelper; import org.stepic.droid.preferences.UserPreferences; import org.stepic.droid.services.ViewPusher; -import org.stepic.droid.storage.operations.Table; import org.stepic.droid.ui.activities.AboutAppActivity; import org.stepic.droid.ui.activities.CertificatesActivity; import org.stepic.droid.ui.activities.CommentsActivity; @@ -41,7 +40,6 @@ import org.stepic.droid.ui.activities.CourseListActivity; import org.stepic.droid.ui.activities.DownloadsActivity; import org.stepic.droid.ui.activities.FeedbackActivity; -import org.stepic.droid.ui.activities.FilterActivity; import org.stepic.droid.ui.activities.LaunchActivity; import org.stepic.droid.ui.activities.LoginActivity; import org.stepic.droid.ui.activities.MainFeedActivity; @@ -511,19 +509,6 @@ public void addCertificateToLinkedIn(CertificateViewItem certificateViewItem) { App.Companion.getAppContext().startActivity(intent); } - @Override - public void showFilterScreen(Fragment sourceFragment, int requestCode, Table courseType) { - Intent intent = new Intent(sourceFragment.getContext(), FilterActivity.class); - int code; - if (courseType == Table.enrolled) { - code = AppConstants.ENROLLED_FILTER; - } else { - code = AppConstants.FEATURED_FILTER; - } - intent.putExtra(FilterActivity.Companion.getFILTER_TYPE_KEY(), code); - sourceFragment.startActivityForResult(intent, requestCode); - } - @Override public void showPdfInBrowserByGoogleDocs(Activity activity, String fullPath) { String googleDocsUrl = "https://docs.google.com/viewer?url="; diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt index b7c01f38f6..dd1cc06951 100644 --- a/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt +++ b/app/src/main/java/org/stepic/droid/core/presenters/PersistentCourseListPresenter.kt @@ -1,7 +1,6 @@ package org.stepic.droid.core.presenters import android.support.annotation.WorkerThread -import org.stepic.droid.analytic.Analytic import org.stepic.droid.concurrency.MainHandler import org.stepic.droid.concurrency.SingleThreadExecutor import org.stepic.droid.core.FilterApplicator @@ -9,7 +8,6 @@ import org.stepic.droid.core.presenters.contracts.CoursesView import org.stepic.droid.di.course_list.CourseListScope import org.stepic.droid.model.Course import org.stepic.droid.model.Progress -import org.stepic.droid.model.StepikFilter import org.stepic.droid.preferences.SharedPreferenceHelper import org.stepic.droid.storage.operations.DatabaseFacade import org.stepic.droid.storage.operations.Table @@ -23,7 +21,6 @@ import javax.inject.Inject @CourseListScope class PersistentCourseListPresenter @Inject constructor( - private val analytic: Analytic, private val databaseFacade: DatabaseFacade, private val singleThreadExecutor: SingleThreadExecutor, private val mainHandler: MainHandler, @@ -38,7 +35,7 @@ class PersistentCourseListPresenter private const val MAX_CURRENT_NUMBER_OF_TASKS = 2 } - private val currentPage = AtomicInteger(1); + private val currentPage = AtomicInteger(1) private val hasNextPage = AtomicBoolean(true) private var currentNumberOfTasks: Int = 0 //only main thread private val isEmptyCourses = AtomicBoolean(false) @@ -55,11 +52,11 @@ class PersistentCourseListPresenter * 3) Save to db * 4) show from cache. (all states) */ - fun downloadData(courseType: Table, applyFilter: Boolean) { - downloadData(courseType, applyFilter, isRefreshing = false) + fun downloadData(courseType: Table) { + downloadData(courseType, isRefreshing = false) } - private fun downloadData(courseType: Table, applyFilter: Boolean, isRefreshing: Boolean, isLoadMore: Boolean = false) { + private fun downloadData(courseType: Table, isRefreshing: Boolean, isLoadMore: Boolean = false) { if (currentNumberOfTasks >= MAX_CURRENT_NUMBER_OF_TASKS) { return } @@ -67,7 +64,7 @@ class PersistentCourseListPresenter view?.showLoading() singleThreadExecutor.execute { try { - downloadDataPlain(isRefreshing, isLoadMore, applyFilter, courseType) + downloadDataPlain(isRefreshing, isLoadMore, courseType) } finally { mainHandler.post { currentNumberOfTasks-- @@ -77,9 +74,9 @@ class PersistentCourseListPresenter } @WorkerThread - private fun downloadDataPlain(isRefreshing: Boolean, isLoadMore: Boolean, applyFilter: Boolean, courseType: Table) { + private fun downloadDataPlain(isRefreshing: Boolean, isLoadMore: Boolean, courseType: Table) { if (!isRefreshing && !isLoadMore) { - getFromDatabaseAndShow(applyFilter, courseType) + getFromDatabaseAndShow(courseType) } else if (hasNextPage.get()) { mainHandler.post { view?.showLoading() @@ -149,11 +146,7 @@ class PersistentCourseListPresenter val filteredCourseList: MutableList = if (courseType == Table.featured) { - if (!applyFilter && !sharedPreferenceHelper.filterForFeatured.contains(StepikFilter.PERSISTENT)) { - filterApplicator.getFilteredFeaturedFromDefault(allCourses) - } else { - filterApplicator.getFilteredFeaturedFromSharedPrefs(allCourses) - } + filterApplicator.filterCourses(allCourses) } else { allCourses } @@ -184,17 +177,13 @@ class PersistentCourseListPresenter } } - private fun getFromDatabaseAndShow(applyFilter: Boolean, courseType: Table) { + private fun getFromDatabaseAndShow(courseType: Table) { val coursesBeforeLoading = databaseFacade.getAllCourses(courseType).filterNotNull() if (coursesBeforeLoading.isNotEmpty()) { val coursesForShow = if (courseType == Table.enrolled) { sortByLastAction(coursesBeforeLoading) } else { - if (!applyFilter && !sharedPreferenceHelper.filterForFeatured.contains(StepikFilter.PERSISTENT)) { - filterApplicator.getFilteredFeaturedFromDefault(coursesBeforeLoading) - } else { - filterApplicator.getFilteredFeaturedFromSharedPrefs(coursesBeforeLoading) - } + filterApplicator.filterCourses(coursesBeforeLoading) } if (coursesForShow.isNotEmpty()) { mainHandler.post { @@ -212,13 +201,13 @@ class PersistentCourseListPresenter } } - fun refreshData(courseType: Table, applyFilter: Boolean, isRefreshing: Boolean) { + fun refreshData(courseType: Table, isRefreshing: Boolean) { if (currentNumberOfTasks >= MAX_CURRENT_NUMBER_OF_TASKS) { return } - currentPage.set(1); + currentPage.set(1) hasNextPage.set(true) - downloadData(courseType, applyFilter, isRefreshing = isRefreshing) + downloadData(courseType, isRefreshing = isRefreshing) } @WorkerThread @@ -251,7 +240,7 @@ class PersistentCourseListPresenter }).toMutableList() } - fun loadMore(courseType: Table, needFilter: Boolean) { - downloadData(courseType, needFilter, isRefreshing = false, isLoadMore = true) + fun loadMore(courseType: Table) { + downloadData(courseType, isRefreshing = false, isLoadMore = true) } } diff --git a/app/src/main/java/org/stepic/droid/di/filters/FilterComponent.kt b/app/src/main/java/org/stepic/droid/di/filters/FilterComponent.kt index 4ebe8e1487..00237a614c 100644 --- a/app/src/main/java/org/stepic/droid/di/filters/FilterComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/filters/FilterComponent.kt @@ -1,7 +1,6 @@ package org.stepic.droid.di.filters import dagger.Subcomponent -import org.stepic.droid.ui.fragments.FilterFragment @FilterScope @Subcomponent @@ -12,5 +11,4 @@ interface FilterComponent { fun build(): FilterComponent } - fun inject(filterFragment: FilterFragment) } diff --git a/app/src/main/java/org/stepic/droid/model/StepikFilter.java b/app/src/main/java/org/stepic/droid/model/StepikFilter.java index c57aeaf7a8..bcf32c4ca3 100644 --- a/app/src/main/java/org/stepic/droid/model/StepikFilter.java +++ b/app/src/main/java/org/stepic/droid/model/StepikFilter.java @@ -2,5 +2,5 @@ //do not rename fields, it will broke analytics public enum StepikFilter { - RUSSIAN, ENGLISH, UPCOMING, ACTIVE, PAST, PERSISTENT + RUSSIAN, ENGLISH } diff --git a/app/src/main/java/org/stepic/droid/preferences/SharedPreferenceHelper.java b/app/src/main/java/org/stepic/droid/preferences/SharedPreferenceHelper.java index 03cc2529ec..f47a0fe68b 100644 --- a/app/src/main/java/org/stepic/droid/preferences/SharedPreferenceHelper.java +++ b/app/src/main/java/org/stepic/droid/preferences/SharedPreferenceHelper.java @@ -17,7 +17,6 @@ import org.stepic.droid.model.StepikFilter; import org.stepic.droid.model.comments.DiscussionOrder; import org.stepic.droid.notifications.model.NotificationType; -import org.stepic.droid.storage.operations.Table; import org.stepic.droid.ui.util.TimeIntervalUtil; import org.stepic.droid.util.AppConstants; import org.stepic.droid.util.DateTimeHelper; @@ -33,10 +32,22 @@ public class SharedPreferenceHelper { private static final String NOTIFICATION_SOUND_DISABLED = "notification_sound"; private static final String TEMP_UPDATE_LINK = "temp_update_link"; - private static final java.lang.String NEED_DROP_116 = "need_drop_116"; - private static final java.lang.String DISCOUNTING_POLICY_DIALOG = "discounting_pol_dialog"; - private static final java.lang.String KEEP_SCREEN_ON_STEPS = "keep_screen_on_steps"; + private static final String NEED_DROP_116 = "need_drop_116"; + private static final String DISCOUNTING_POLICY_DIALOG = "discounting_pol_dialog"; + private static final String KEEP_SCREEN_ON_STEPS = "keep_screen_on_steps"; private static final String ROTATE_PREF = "rotate_pref"; + private static final String SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING = "before116"; + private static final String NOTIFICATION_LEARN_DISABLED = "notification_disabled_by_user"; + private static final String NOTIFICATION_COMMENT_DISABLED = "notification_comment_disabled"; + private static final String NOTIFICATION_TEACH_DISABLED = "notification_teach_disabled"; + private static final String NOTIFICATION_REVIEW_DISABLED = "notification_review_disabled"; + private static final String NOTIFICATION_OTHER_DISABLED = "notification_other_disabled"; + private static final String NOTIFICATION_VIBRATION_DISABLED = "not_vibrat_disabled"; + private final static String ONE_DAY_NOTIFICATION = "one_day_notification"; + private final static String SEVEN_DAY_NOTIFICATION = "seven_day_notification"; + private static final String FILTER_RUSSIAN_LANGUAGE = "russian_lang"; + private static final String FILTER_ENGLISH_LANGUAGE = "english_lang"; + private final String ACCESS_TOKEN_TIMESTAMP = "access_token_timestamp"; private final String UPDATING_TIMESTAMP = "updating_timestamp"; private final String AUTH_RESPONSE_JSON = "auth_response_json"; @@ -50,12 +61,6 @@ public class SharedPreferenceHelper { private final String VIDEO_RATE_PREF_KEY = "video_rate_pref_key"; private final String VIDEO_EXTERNAL_PREF_KEY = "video_external_pref_key"; private final String GCM_TOKEN_ACTUAL = "gcm_token_actual"; - private final String NOTIFICATION_LEARN_DISABLED = "notification_disabled_by_user"; - private final String NOTIFICATION_COMMENT_DISABLED = "notification_comment_disabled"; - private final String NOTIFICATION_TEACH_DISABLED = "notification_teach_disabled"; - private final String NOTIFICATION_REVIEW_DISABLED = "notification_review_disabled"; - private final String NOTIFICATION_OTHER_DISABLED = "notification_other_disabled"; - private final String NOTIFICATION_VIBRATION_DISABLED = "not_vibrat_disabled"; private final String SD_CHOSEN = "sd_chosen"; private final String FIRST_TIME_LAUNCH = "first_time_launch"; private final String SCHEDULED_LINK_CACHED = "scheduled_cached"; @@ -64,42 +69,29 @@ public class SharedPreferenceHelper { private final String VIDEO_QUALITY_EXPLANATION = "video_quality_explanation"; private final String NEED_DROP_114 = "need_drop_114"; private final String REMIND_CLICK = "remind_click"; - private final static String ONE_DAY_NOTIFICATION = "one_day_notification"; - private final static String SEVEN_DAY_NOTIFICATION = "seven_day_notification"; private final String ANY_STEP_SOLVED = "any_step_solved"; private final String NUMBER_OF_STEPS_SOLVED = "number_of_steps_solved"; private final String NEW_USER_ALARM_TIMESTAMP = "new_user_alarm_timestamp"; private final String NUMBER_OF_SHOWN_STREAK_DIALOG = "number_of_shown_streak_dialog"; private final String STREAK_DIALOG_SHOWN_TIMESTAMP = "streak_dialog_shown_timestamp"; private final String STREAK_NUMBER_OF_IGNORED = "streak_number_of_ignored"; - - private final String FILTER_PERSISTENT = "filter_persistent"; - private final String FILTER_RUSSIAN_LANGUAGE = "russian_lang"; - private final String FILTER_ENGLISH_LANGUAGE = "english_lang"; - private final String FILTER_UPCOMING = "filter_upcoming"; - private final String FILTER_ACTIVE = "filter_active"; - private final String FILTER_PAST = "filter_past"; private final String TIME_NOTIFICATION_CODE = "time_notification_code"; private final String STREAK_NOTIFICATION = "streak_notification"; - private final String USER_START_KEY = "user_start_app"; - private final String RATE_LAST_TIMESTAMP = "rate_last_timestamp"; private final String RATE_TIMES_SHOWN = "rate_times_shown"; private final String RATE_WAS_HANDLED = "rate_was_handled"; - private Context context; - private Analytic analytic; - private DefaultFilter defaultFilter; + private final Context context; + private final Analytic analytic; + private final DefaultFilter defaultFilter; @Inject public SharedPreferenceHelper(Analytic analytic, DefaultFilter defaultFilter, Context context) { this.analytic = analytic; this.defaultFilter = defaultFilter; this.context = context; - - resetFiltersForFeatured(); //reset on app recreating and on destroy course's Fragments } /** @@ -245,6 +237,15 @@ private void onShowStreakDialog(int streakDialogShownNumber) { put(PreferenceType.LOGIN, NUMBER_OF_SHOWN_STREAK_DIALOG, streakDialogShownNumber + 1); } + public void setNeedResolveLanguage() { + put(SharedPreferenceHelper.PreferenceType.DEVICE_SPECIFIC, SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING, true); + } + + private boolean needResolveLanguage() { + return getBoolean(SharedPreferenceHelper.PreferenceType.DEVICE_SPECIFIC, SHOW_FILTER_FEATURE_WITH_LANGUAGE_RESOLVING, false); //by default user before 116 and we don't show he/she only language courses #Apps-430 + + } + public enum NotificationDay { DAY_ONE(ONE_DAY_NOTIFICATION), DAY_SEVEN(SEVEN_DAY_NOTIFICATION); @@ -269,13 +270,6 @@ public void setNotificationShown(NotificationDay day) { put(PreferenceType.DEVICE_SPECIFIC, day.getInternalNotificationKey(), true); } - - public void onTryDiscardFilters(Table type) { - if (type == Table.featured) { - resetFiltersForFeatured(); - } - } - public int incrementNumberOfLaunches() { int numberOfLaunches = getInt(PreferenceType.DEVICE_SPECIFIC, USER_START_KEY); int newValue = numberOfLaunches + 1; @@ -409,34 +403,28 @@ public void afterNeedDropCoursesIn114() { put(PreferenceType.DEVICE_SPECIFIC, NEED_DROP_116, false); } - private void resetFiltersForFeatured() { - if (!getBoolean(PreferenceType.FEATURED_FILTER, FILTER_PERSISTENT, defaultFilter.getDefaultFeatured(StepikFilter.PERSISTENT))) { - clear(PreferenceType.FEATURED_FILTER); - } - } - private String getPrefNameForFilter(StepikFilter filter) { switch (filter) { - case RUSSIAN: return FILTER_RUSSIAN_LANGUAGE; - case ENGLISH: return FILTER_ENGLISH_LANGUAGE; - case UPCOMING: return FILTER_UPCOMING; - case ACTIVE: return FILTER_ACTIVE; - case PAST: return FILTER_PAST; - case PERSISTENT: return FILTER_PERSISTENT; - default: throw new IllegalArgumentException("Unknown StepikFilter type: " + filter); + case RUSSIAN: + return FILTER_RUSSIAN_LANGUAGE; + case ENGLISH: + return FILTER_ENGLISH_LANGUAGE; + default: + throw new IllegalArgumentException("Unknown StepikFilter type: " + filter); } } public EnumSet getFilterForFeatured() { EnumSet filters = EnumSet.noneOf(StepikFilter.class); + boolean needResolveLanguage = needResolveLanguage(); for (StepikFilter filter : StepikFilter.values()) { - appendValueForFilter(PreferenceType.FEATURED_FILTER, filters, getPrefNameForFilter(filter), filter, defaultFilter.getDefaultFeatured(filter)); + appendValueForFilter(filters, filter, defaultFilter.getDefaultFilter(filter, needResolveLanguage)); } return filters; } - private void appendValueForFilter(PreferenceType preferenceType, EnumSet filter, String key, StepikFilter value, boolean defaultValue) { - if (getBoolean(preferenceType, key, defaultValue)) { + private void appendValueForFilter(EnumSet filter, StepikFilter value, boolean defaultValue) { + if (getBoolean(PreferenceType.FEATURED_FILTER, getPrefNameForFilter(value), defaultValue)) { filter.add(value); } } @@ -451,7 +439,7 @@ private void saveValueFromFilterIfExist(PreferenceType preferenceType, EnumSet resolve language + sharedPreferenceHelper.setNeedResolveLanguage(); //if user 1st time and v1.16 or more --> resolve language } else if (!sharedPreferenceHelper.isScheduleAdded()) { databaseFacade.dropOnlyCourseTable(); sharedPreferenceHelper.afterScheduleAdded(); diff --git a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt index 45785f7ece..71543b1fe5 100644 --- a/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt +++ b/app/src/main/java/org/stepic/droid/ui/custom/CoursesCarouselView.kt @@ -353,7 +353,7 @@ constructor( private fun downloadData() { info.table?.let { - courseListPresenter.refreshData(it, false, false) + courseListPresenter.refreshData(it, false) } if (info.table == null) { diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt index 6298a48e5b..d40d115b86 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/FastContinueFragment.kt @@ -97,7 +97,7 @@ class FastContinueFragment : FragmentBase(), //refresh the last course only when view is created if (sharedPreferenceHelper.authResponseFromStore != null) { - courseListPresenter.downloadData(Table.enrolled, applyFilter = false) + courseListPresenter.downloadData(Table.enrolled) } else { analytic.reportEvent(Analytic.FastContinue.AUTH_SHOWN) showPlaceholder(R.string.placeholder_login, { _ -> @@ -149,7 +149,7 @@ class FastContinueFragment : FragmentBase(), showPlaceholder(R.string.internet_problem, { _ -> analytic.reportEvent(Analytic.FastContinue.NO_INTERNET_CLICK) if (StepikUtil.isInternetAvailable()) { - courseListPresenter.downloadData(Table.enrolled, applyFilter = false) + courseListPresenter.downloadData(Table.enrolled) } }) } @@ -210,7 +210,7 @@ class FastContinueFragment : FragmentBase(), //Client override fun onSuccessDropCourse(course: Course) { //reload the last course - courseListPresenter.refreshData(Table.enrolled, applyFilter = false, isRefreshing = true) + courseListPresenter.refreshData(Table.enrolled, isRefreshing = true) } override fun onFailDropCourse(course: Course) { @@ -280,6 +280,6 @@ class FastContinueFragment : FragmentBase(), } override fun onSuccessJoin(joinedCourse: Course) { - showCourses(mutableListOf(joinedCourse)) + showCourses(mutableListOf(joinedCourse)) } } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FilterFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/FilterFragment.kt deleted file mode 100644 index ed7bebf6a0..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FilterFragment.kt +++ /dev/null @@ -1,152 +0,0 @@ -package org.stepic.droid.ui.fragments - -import android.app.Activity -import android.os.Bundle -import android.view.* -import android.widget.Checkable -import kotlinx.android.synthetic.main.fragment_filter.* -import org.stepic.droid.R -import org.stepic.droid.analytic.Analytic -import org.stepic.droid.base.App -import org.stepic.droid.base.FragmentBase -import org.stepic.droid.core.presenters.FilterPresenter -import org.stepic.droid.core.presenters.contracts.FilterView -import org.stepic.droid.model.StepikFilter -import org.stepic.droid.storage.operations.Table -import org.stepic.droid.ui.util.initCenteredToolbar -import org.stepic.droid.util.AppConstants -import java.util.* -import javax.inject.Inject - -class FilterFragment : FragmentBase(), - FilterView { - - companion object { - - private val filterCourseTypeKey = "filterCourseType" - - fun newInstance(filterCourseTypeCode: Int): FilterFragment { - val args = Bundle() - args.putInt(filterCourseTypeKey, filterCourseTypeCode) - val fragment = FilterFragment() - fragment.arguments = args - return fragment - } - } - - @Inject - lateinit var filterPresenter: FilterPresenter - - private lateinit var courseType: Table - - override fun injectComponent() { - App - .component() - .filterComponentBuilder() - .build() - .inject(this) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - retainInstance = true - setHasOptionsMenu(true) - - val filterCode = arguments.getInt(filterCourseTypeKey) - - courseType = when (filterCode) { - AppConstants.ENROLLED_FILTER -> Table.enrolled - AppConstants.FEATURED_FILTER -> Table.featured - else -> throw IllegalStateException("course type for filters should be set") - } - } - - override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater?.inflate(R.layout.fragment_filter, container, false) - } - - override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - nullifyActivityBackground() - initToolbar() - - acceptButton.setOnClickListener { - analytic.reportEvent(Analytic.Interaction.CLICK_ACCEPT_FILTER_BUTTON) - filterPresenter.acceptFilter(getCurrentFilterFromUI(), courseType) - } - - cancelButton.setOnClickListener { activity.finish() } - filterPresenter.attachView(this) - filterPresenter.initFiltersIfNeed(courseType) - } - - private fun initToolbar() { - initCenteredToolbar(R.string.filter_title, true, getCloseIconDrawableRes()) - } - - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - super.onCreateOptionsMenu(menu, inflater) - inflater?.inflate(R.menu.filter_accept_menu, menu) - } - - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item!!.itemId) { - android.R.id.home -> { - // Respond to the action bar's Up/Home button - activity.finish() - return true - } - R.id.accept_action -> { - filterPresenter.acceptFilter(getCurrentFilterFromUI(), courseType) - return true - } - } - return super.onOptionsItemSelected(item) - } - - - override fun onDestroyView() { - acceptButton.setOnClickListener(null) - cancelButton.setOnClickListener(null) - filterPresenter.detachView(this) - super.onDestroyView() - } - - private fun applyFilterToView(filters: EnumSet, stepikFilterValue: StepikFilter, checkable: Checkable) { - checkable.isChecked = filters.contains(stepikFilterValue) - } - - private fun getCurrentFilterFromUI(): EnumSet { - val filter = EnumSet.noneOf(StepikFilter::class.java) - appendToFilter(filter, StepikFilter.RUSSIAN, languageRuCheckBox.isChecked) - appendToFilter(filter, StepikFilter.ENGLISH, languageEnCheckBox.isChecked) - appendToFilter(filter, StepikFilter.UPCOMING, upcomingCheckBox.isChecked) - appendToFilter(filter, StepikFilter.ACTIVE, activeCheckBox.isChecked) - appendToFilter(filter, StepikFilter.PAST, pastCheckBox.isChecked) - appendToFilter(filter, StepikFilter.PERSISTENT, persistentCheckBox.isChecked) - return filter - } - - private fun appendToFilter(filter: EnumSet, stepikFilterValue: StepikFilter, needAppend: Boolean) { - if (needAppend) { - filter.add(stepikFilterValue) - } - } - - override fun onFilterAccepted() { - //filter is accepted, close - activity.setResult(Activity.RESULT_OK) - activity.finish() - } - - override fun onFiltersPreparedForView(filters: EnumSet) { - //set filter, when it is prepared: - applyFilterToView(filters, StepikFilter.RUSSIAN, languageRuCheckBox) - applyFilterToView(filters, StepikFilter.ENGLISH, languageEnCheckBox) - applyFilterToView(filters, StepikFilter.UPCOMING, upcomingCheckBox) - applyFilterToView(filters, StepikFilter.ACTIVE, activeCheckBox) - applyFilterToView(filters, StepikFilter.PAST, pastCheckBox) - applyFilterToView(filters, StepikFilter.PERSISTENT, persistentCheckBox) - } - -} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java deleted file mode 100644 index a306b9a8e0..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/FindCoursesFragment.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.stepic.droid.ui.fragments; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.View; - -import org.stepic.droid.R; -import org.stepic.droid.base.CoursesDatabaseFragmentBase; -import org.stepic.droid.storage.operations.Table; -import org.stepic.droid.ui.listeners.OnRootTouchedListener; -import org.stepic.droid.ui.util.ToolbarHelperKt; - -public class FindCoursesFragment extends CoursesDatabaseFragmentBase { - - public static FindCoursesFragment newInstance() { - return new FindCoursesFragment(); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - setHasOptionsMenu(true); - super.onViewCreated(view, savedInstanceState); - ToolbarHelperKt.initCenteredToolbar(this, getTitle(), false); - rootView.setParentTouchEvent(new OnRootTouchedListener() { - @Override - public void makeBeforeChildren() { - collapseAndHide(true); - } - }); - } - - @Override - public void onDestroyView() { - if (listOfCoursesView != null) { - listOfCoursesView.setOnFocusChangeListener(null); - } - super.onDestroyView(); - } - - private void collapseAndHide(boolean rootHandle) { - } - - @Override - protected Table getCourseType() { - return Table.featured; - } - - protected String getTitle() { - return getString(R.string.catalog_title); - } -} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/MyCoursesFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/MyCoursesFragment.kt index c236f87c2c..08dc415244 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/MyCoursesFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/MyCoursesFragment.kt @@ -1,9 +1,8 @@ package org.stepic.droid.ui.fragments import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater import android.view.View +import org.jetbrains.annotations.NotNull import org.stepic.droid.R import org.stepic.droid.base.CoursesDatabaseFragmentBase import org.stepic.droid.storage.operations.Table @@ -15,12 +14,11 @@ class MyCoursesFragment : CoursesDatabaseFragmentBase() { fun newInstance() = MyCoursesFragment() } + @NotNull override fun getCourseType() = Table.enrolled override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) this.initCenteredToolbar(R.string.my_courses_title) } - - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {} } diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt index 1ca0c05520..92d9569e12 100644 --- a/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/fragments/PopularCoursesAloneFragment.kt @@ -1,17 +1,25 @@ package org.stepic.droid.ui.fragments -import android.view.Menu -import android.view.MenuInflater +import android.os.Bundle +import android.view.View +import org.jetbrains.annotations.NotNull import org.stepic.droid.R +import org.stepic.droid.base.CoursesDatabaseFragmentBase +import org.stepic.droid.storage.operations.Table +import org.stepic.droid.ui.util.initCenteredToolbar -open class PopularCoursesAloneFragment : FindCoursesFragment() { +open class PopularCoursesAloneFragment : CoursesDatabaseFragmentBase() { companion object { + fun newInstance(): PopularCoursesAloneFragment = PopularCoursesAloneFragment() } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - //no-op + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + this.initCenteredToolbar(R.string.popular_courses_title, false) } - override fun getTitle(): String = getString(R.string.popular_courses_title) + @NotNull + override fun getCourseType(): Table = Table.featured + } diff --git a/app/src/main/res/drawable-hdpi/ic_action_tune.png b/app/src/main/res/drawable-hdpi/ic_action_tune.png deleted file mode 100644 index 8161c46a56f0e345f61b215be9c0b5bd09aef50d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 440 zcmV;p0Z0CcP)J13x1Pm3u7G0+;i~-ulNTCJkzne*ZdAs|v zCDiPrn(^QWq|3U8DR;SALx4t`o<&dyvrWv2j4Bm4^xoE`uYR?W@1zg zZAGCmfWkLURjv$UO!iX^O#zD4*8Wv21C=x}?iffvG43>Frrq)Xy3ACe+8Lwi1$65- iHb&h6rtu??PO)z@{YErJurc`n0000TF$)Wm4IJF|%*Rgx6`%0qu`s=Kgh^-OnWi_*K*Qhj@bDxU z)-+5Baf#)g5bHWwVbN;V8;2ys+)pI>XxMpp)rmwmtX|QuQ$mZst746+`Wf>jOO!Uq zt%`Keu+ijO#JIg-0`rQv#e&I-o+qbBFkigNz>xU2Ow!(>8RS(4Pgg&ebxsLQ0P3D& AHUIzs diff --git a/app/src/main/res/drawable-xhdpi/ic_action_tune.png b/app/src/main/res/drawable-xhdpi/ic_action_tune.png deleted file mode 100644 index 9882f12624ab40b647fa660b480b7054e2ab4844..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 390 zcmV;10eSw3P)0j4CO(k2b?8vkr4lP$RNZfsf4<&tMB)VQRG`~E(9cU z_t2ME03g(YHsxjjn1$*!Np=k=)!&H7umMSRnnj<5902Ab|0RI9vrvuzxLGJ~3GL}s z+Gt2MTX)NCqeV*yQNZ#Y`4sxsFD2pwu{k6m#IXQCSR#tIUQeC@U=}hsa;#14QNnxg zY0X-3_d+?262|tJlVpwnxLGJ~32}^b=gEth3y?b(031WH7h9*#07zi4S+rRwI5No@hm;e9( diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_tune.png b/app/src/main/res/drawable-xxhdpi/ic_action_tune.png deleted file mode 100644 index 62030d594e0c216a595f309a8e0540e711da492c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmV+l0`>igP)=B%5CG+wP{IfDCmQpD6n>P8yZ|@+DIbXGV8$8GB!z>d({W;K*-MKKq-AwFpH1a> zMF~{!i4y>jUx^4#FvTwKh;d1%xZAhlk09xY~!yw^T z1rUI2X>@T0)phf2TarGys$73Qx9`5l5FqEA>ICb$_8`qH=@g4hNcw!s`+aBux#rV# zt+;-1z_`L(6H?LwkN^xoYXU@)R_2FUhcE7!pOuE^%K=0sZF3TXFlfUD9giRT-R{j> z7NnH+Hgx%;lP)zhUkf0C7JvYx*-(#TF$jYm2|UqJ-1|6&PO;Oe`5Ff2jj{P0k6v6y zF$C!M2bcqpc#4Yya&{B}B8P>w&8}E_un;Izt?P#wxhVMB&{_?JHGg1Ub|rJcmPpJ zYn_>n#~=*CARB>#qmwQ*3SOUi>HrcD0ti61U4}szgh4g}7-Zx31C+FESO{JoH~;_u M07*qoM6N<$g7m@TQUCw| diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_tune.png b/app/src/main/res/drawable-xxxhdpi/ic_action_tune.png deleted file mode 100644 index 0727907ebd40e6d39de0a761d77dd3f53ed26031..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 796 zcmV+%1LOROP)SOEi*m=*6oy2rA z@Yj{VrfcgoJ|Lj;AV2^DIuq#JJTm|Roe6Yqo*96E&ICF)&kR67X9As@X9gf(T>|5H z{7SWWyM6A@=eNsRy?VGAfPl4z)*tO400DOdxCJc+1Z#kKhHwiq16Jt~pa_}E|Gj{5 zJbsuNMbclV>GYCHpacxVa2dEG=hL2z-V;@LZcueuL{ zDn~Oq6^ZO0WYm*nMW64gWC)laKuekxxe!nRtz{Ji zw4_;)3jr0-T2?_oOPUqA5KsZFWfcUpq*;-xSU~VxknEy5S0kPS<`Wz9@BMW9Q~h6d ztVRIGQWARC_#}w{1aLCWc8^t4n3Hkh$FHMi5FiM0GA<2B4WJggpvbu(IYHDm?%}tg zlAt+&?*V4ODm?-eA#*tb%z#yT1Smr0as-$GtMmv^gv{j#FauWU5ugZBUPPeydq7ck zf+Yb2NJQQM1bF$%>UAQ5>35a8u2vm-zv@&+Kl%U5PcfJEdCK!BI8 a%>E5?Y0000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -